修复联机阵营问题,漫画入版

This commit is contained in:
wuwenbo 2026-02-05 15:22:19 +08:00
parent ba1100da82
commit dd97856d22
12 changed files with 911 additions and 126 deletions

View File

@ -205,6 +205,15 @@ namespace RuntimeData
MultiCivs?.Clear();
_memberCivs?.Clear();
}
public void ChangeByMapConfig(MapConfig other)
{
GameMode = other.GameMode;
IsCustomMap = other.IsCustomMap;
MapName = other.MapName;
MatchSettlement = other.MatchSettlement;
PlayerSettlements = other.PlayerSettlements;
}
}

View File

@ -7,10 +7,11 @@
using MemoryPack;
using UnityEngine;
namespace TH1_Logic.Comic
{
// 淡入 淡出 左滑入 左滑出 右滑入 右滑出 上滑入 上滑出 下滑入 下滑出 字体浮现
// 淡入 淡出 左滑入 左滑出 右滑入 右滑出 上滑入 上滑出 下滑入 下滑出 字体浮现 整体上移入 整体上移出
public enum ComicActionType
{
None = 0,
@ -25,19 +26,22 @@ namespace TH1_Logic.Comic
SlideInDown = 9,
SlideOutDown = 10,
TextAppear = 11,
AllSlideInUp = 12,
AllSlideOutUp = 13,
}
[MemoryPackable]
public partial class ComicAction
{
public uint TargetId;
public int TargetId;
public ComicActionType ActionType;
public float Duration;
[MemoryPackIgnore] public float StartTime;
[MemoryPackIgnore] public bool IsFinished;
[MemoryPackIgnore]
public int Index;
public ComicAction()
{
TargetId = 0;
@ -51,15 +55,394 @@ namespace TH1_Logic.Comic
{
public static ComicActionLogic GetActionLogic(ComicActionType actionType)
{
return null;
return actionType switch
{
ComicActionType.FadeIn => new FadeInComicActionLogic(),
ComicActionType.FadeOut => new FadeOutComicActionLogic(),
ComicActionType.SlideInLeft => new SlideInLeftComicActionLogic(),
ComicActionType.SlideOutLeft => new SlideOutLeftComicActionLogic(),
ComicActionType.SlideInRight => new SlideInRightComicActionLogic(),
ComicActionType.SlideOutRight => new SlideOutRightComicActionLogic(),
ComicActionType.SlideInUp => new SlideInUpComicActionLogic(),
ComicActionType.SlideOutUp => new SlideOutUpComicActionLogic(),
ComicActionType.SlideInDown => new SlideInDownComicActionLogic(),
ComicActionType.SlideOutDown => new SlideOutDownComicActionLogic(),
ComicActionType.TextAppear => new TextAppearComicActionLogic(),
ComicActionType.AllSlideInUp => new AllSlideInUpComicActionLogic(),
ComicActionType.AllSlideOutUp => new AllSlideOutUpComicActionLogic(),
_ => null
};
}
}
public abstract class ComicActionLogic
{
public abstract void SetStartState(ComicItemMono comicItem, ComicAction action);
public abstract void SetEndState(ComicItemMono comicItem, ComicAction action);
public abstract bool SetUpdateAction(ComicItemMono comicItem, ComicAction action, float progress);
public abstract void SetStartState(ComicData data, ComicSubItem item, ComicAction action);
public abstract void SetEndState(ComicData data, ComicSubItem item, ComicAction action);
public abstract void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio);
}
// 淡入 Action
public class FadeInComicActionLogic : ComicActionLogic
{
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
var color = data.Mono.BlackImage.color;
color.a = 1;
data.Mono.BlackImage.color = color;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
var color = data.Mono.BlackImage.color;
color.a = 0;
data.Mono.BlackImage.color = color;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
var color = data.Mono.BlackImage.color;
color.a = 1 - ratio;
data.Mono.BlackImage.color = color;
}
}
// 淡出 Action
public class FadeOutComicActionLogic : ComicActionLogic
{
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
var color = data.Mono.BlackImage.color;
color.a = 0;
data.Mono.BlackImage.color = color;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
var color = data.Mono.BlackImage.color;
color.a = 1;
data.Mono.BlackImage.color = color;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
var color = data.Mono.BlackImage.color;
color.a = ratio;
data.Mono.BlackImage.color = color;
}
}
// 左滑入 Action
public class SlideInLeftComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = -1400;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = -1400 + (item.PositionX + 1400) * ratio;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 左滑出 Action
public class SlideOutLeftComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = -1400;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX - (item.PositionX + 1400) * ratio;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 右滑入 Action
public class SlideInRightComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 1400;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = 1400 - (1400 - item.PositionX) * ratio;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 右滑出 Action
public class SlideOutRightComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 1400;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX + (1400 - item.PositionX) * ratio;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 上滑入 Action从上方进入
public class SlideInUpComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = 700;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX;
_pos.y = 700 - (700 - item.PositionY) * ratio;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 上滑出 Action向上方离开
public class SlideOutUpComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = 700;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY + (700 - item.PositionY) * ratio;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 下滑入 Action从下方进入
public class SlideInDownComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = -700;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX;
_pos.y = -700 + (item.PositionY + 700) * ratio;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 下滑出 Action向下方离开
public class SlideOutDownComicActionLogic : ComicActionLogic
{
private Vector2 _pos = new Vector2();
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = item.PositionX;
_pos.y = -700;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = item.PositionX;
_pos.y = item.PositionY - (item.PositionY + 700) * ratio;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 字体浮现 Action
public class TextAppearComicActionLogic : ComicActionLogic
{
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
if (item.Mono.TextMono != null)
{
item.Mono.TextMono.ForceMeshUpdate();
item.Mono.TextMono.maxVisibleCharacters = 0;
}
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
if (item.Mono.TextMono != null)
{
item.Mono.TextMono.maxVisibleCharacters = item.Mono.TextMono.textInfo.characterCount;
}
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
if (item.Mono.TextMono != null)
{
int visibleCount = (int)(item.Mono.TextMono.textInfo.characterCount * ratio);
item.Mono.TextMono.maxVisibleCharacters = visibleCount;
}
}
}
// 整体上移入 Action
public class AllSlideInUpComicActionLogic : ComicActionLogic
{
private Vector2 _pos;
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 0;
_pos.y = -data.Mono.Rect.rect.height;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 0;
_pos.y = 0;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = 0;
_pos.y = -data.Mono.Rect.rect.height * (1 - ratio);
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
// 整体上移出 Action
public class AllSlideOutUpComicActionLogic : ComicActionLogic
{
private Vector2 _pos;
public override void SetStartState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 0;
_pos.y = 0;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetEndState(ComicData data, ComicSubItem item, ComicAction action)
{
_pos.x = 0;
_pos.y = data.Mono.Rect.rect.height;
item.Mono.ItemRect.anchoredPosition = _pos;
}
public override void SetUpdateAction(ComicData data, ComicSubItem item, ComicAction action, float ratio)
{
_pos.x = 0;
_pos.y = data.Mono.Rect.rect.height * ratio;
item.Mono.ItemRect.anchoredPosition = _pos;
}
}
}

View File

@ -6,7 +6,6 @@
*/
using System.Collections.Generic;
using Logic.CrashSight;
using UnityEngine;
@ -27,26 +26,119 @@ namespace TH1_Logic.Comic
{
private GameObject _comicRoot;
private ComicData _comicData;
private ComicMono _comicMono;
private Dictionary<uint, ComicItemMono> _comicItems = new Dictionary<uint, ComicItemMono>();
private ComicSheet _comicSheet;
private ComicState _state = ComicState.None;
private int _actionIndex = 0;
private float _progress = 0f;
private float _speed = 1f;
private float _progress = 0f;
private float _duration = 10f;
private int _actionIndex = 0;
private int _comicMaxIndex = 0;
private ComicState _state = ComicState.None;
public GameObject ComicRoot => _comicRoot;
public ComicData ComicData => _comicData;
public ComicSheet ComicSheet => _comicSheet;
public ComicState State => _state;
public int ActionIndex => _actionIndex;
public int MaxIndex => _comicMaxIndex;
public float Progress => _progress;
public float Duration => _duration;
public void Init(ComicData data, GameObject comicRoot)
public void Init(ComicSheet sheet, GameObject comicRoot)
{
Clear();
if (!comicRoot) return;
_comicRoot = comicRoot;
_comicSheet = sheet;
var comicPrefab = ComicManager.Instance.LoadPrefab("ComicPrefab");
if (!comicPrefab)
{
LogSystem.LogError($"ComicControl Init Error ComicPrefab is null");
return;
}
var dialogPrefab = ComicManager.Instance.LoadPrefab("DialogPrefab");
if (!dialogPrefab)
{
LogSystem.LogError($"ComicControl Init Error DialogPrefab is null");
return;
}
var imagePrefab = ComicManager.Instance.LoadPrefab("ImagePrefab");
if (!imagePrefab)
{
LogSystem.LogError($"ComicControl Init Error ImagePrefab is null");
return;
}
var index = 0;
for (int i = 0; i < _comicSheet.ComicDatas.Count; i++)
{
var data = _comicSheet.ComicDatas[i];
var comicInstance = Object.Instantiate(comicPrefab, _comicRoot.transform, false);
data.Mono = comicInstance.GetComponent<ComicMono>();
if (!data.Mono)
{
LogSystem.LogError($"ComicControl Init Error _comicMono is null");
return;
}
data.ApplyToMono();
foreach (var item in data.SubItems)
{
GameObject instance = null;
if(item.ItemType == ComicSubItemType.Image)
instance = Object.Instantiate(imagePrefab, data.Mono.ItemRoot, false);
if(item.ItemType == ComicSubItemType.Dialog)
instance = Object.Instantiate(dialogPrefab, data.Mono.ItemRoot, false);
var itemMono = instance?.GetComponent<ComicItemMono>();
if (!itemMono)
{
LogSystem.LogError($"ComicControl Init Error itemMono is null");
continue;
}
item.Mono = itemMono;
item.ApplyToItemMono();
}
if (i == 0)
{
data.InitFadeInAction(ComicActionType.FadeIn);
}
else
{
data.InitFadeInAction(ComicActionType.AllSlideInUp);
}
if (i == _comicSheet.ComicDatas.Count - 1)
{
data.InitFadeOutAction(ComicActionType.FadeOut);
}
else
{
data.InitFadeOutAction(ComicActionType.AllSlideOutUp);
}
data.FadeInAction.Index = index;
foreach (var action in data.Actions)
{
index++;
action.Index = index;
}
index++;
data.FadeOutAction.Index = index;
}
_comicMaxIndex = index;
_actionIndex = 0;
_state = ComicState.Prepared;
}
public void PreviewComicData(ComicData data, GameObject comicRoot)
{
Clear();
if (!comicRoot) return;
_comicRoot = comicRoot;
_comicData = data;
var comicPrefab = ComicManager.Instance.LoadPrefab("ComicPrefab");
if (!comicPrefab)
@ -54,47 +146,57 @@ namespace TH1_Logic.Comic
LogSystem.LogError($"ComicControl Init Error ComicPrefab is null");
return;
}
var dialogPrefab = ComicManager.Instance.LoadPrefab("DialogPrefab");
if (!dialogPrefab)
{
LogSystem.LogError($"ComicControl Init Error DialogPrefab is null");
return;
}
var imagePrefab = ComicManager.Instance.LoadPrefab("ImagePrefab");
if (!imagePrefab)
{
LogSystem.LogError($"ComicControl Init Error ImagePrefab is null");
return;
}
var comicInstance = Object.Instantiate(comicPrefab, _comicRoot.transform, false);
comicInstance.transform.localPosition = Vector3.zero;
_comicMono = comicInstance.GetComponent<ComicMono>();
if (!_comicMono)
data.Mono = comicInstance.GetComponent<ComicMono>();
if (!data.Mono)
{
LogSystem.LogError($"ComicControl Init Error _comicMono is null");
return;
}
_comicMono.BackgroundImage.sprite = ComicManager.Instance.GetImage(_comicData.Background.ImageName);
foreach (var item in _comicData.SubItems)
data.ApplyToMono();
foreach (var item in data.SubItems)
{
var itemPrefab = ComicManager.Instance.LoadPrefab("ComicItemPrefab");
if (!itemPrefab)
{
LogSystem.LogError($"ComicControl Init Error itemPrefab is null");
continue;
}
var itemInstance = Object.Instantiate(itemPrefab, _comicMono.ItemRoot, false);
var itemMono = itemInstance.GetComponent<ComicItemMono>();
GameObject instance = null;
if(item.ItemType == ComicSubItemType.Image)
instance = Object.Instantiate(imagePrefab, data.Mono.ItemRoot, false);
if(item.ItemType == ComicSubItemType.Dialog)
instance = Object.Instantiate(dialogPrefab, data.Mono.ItemRoot, false);
var itemMono = instance?.GetComponent<ComicItemMono>();
if (!itemMono)
{
LogSystem.LogError($"ComicControl Init Error itemMono is null");
continue;
}
_comicItems[item.Id] = itemMono;
itemInstance.transform.localPosition = new Vector3(item.PositionX, item.PositionY, 0);
var rectTransform = comicInstance.GetComponent<RectTransform>();
if (rectTransform)
{
rectTransform.sizeDelta = new Vector2(item.Width, item.Height);
}
item.Mono = itemMono;
item.ApplyToItemMono();
}
_state = ComicState.Prepared;
}
public void Next()
{
if (_state == ComicState.Ended) return;
if (_state == ComicState.Playing)
{
Update(Mathf.Max(_duration - _progress, 0f));
return;
}
if (_state == ComicState.Prepared)
{
@ -106,37 +208,42 @@ namespace TH1_Logic.Comic
if (_state == ComicState.Pausing)
{
if (_actionIndex >= _comicData.Actions.Count - 1)
if (_actionIndex >= _comicMaxIndex)
{
_state = ComicState.Ended;
return;
}
_actionIndex++;
_progress = 0;
_state = ComicState.Playing;
}
if (_state == ComicState.Playing) Update();
}
public void Update()
public void Update(float deltaTime = 0.016f)
{
if (_state != ComicState.Playing) return;
_progress += Time.deltaTime * _speed;
_progress += deltaTime * _speed;
for (int i = 0; i < _comicData.Actions.Count; i++)
foreach (var data in _comicSheet.ComicDatas)
{
var action = _comicData.Actions[i];
var logic = ComicActionLogicFactory.GetActionLogic(action.ActionType);
var item = _comicItems[action.TargetId];
if (i < _actionIndex)logic.SetEndState(item, action);
if (i == _actionIndex)
foreach (var action in data.Actions)
{
logic.SetUpdateAction(item, action, _progress);
if (_progress >= action.Duration) _state = ComicState.Pausing;
}
var logic = ComicActionLogicFactory.GetActionLogic(action.ActionType);
var item = data.GetSubItemById(action.TargetId);
if (action.Index < _actionIndex)logic.SetEndState(data, item, action);
var maxDuration = 0f;
if (action.Index == _actionIndex)
{
var ratio = Mathf.Min(1, _progress / _duration);
logic.SetUpdateAction(data, item, action, ratio);
if(action.Duration > maxDuration) maxDuration = action.Duration;
}
_duration = maxDuration;
if (_progress >= _duration) _state = ComicState.Pausing;
if (i > _actionIndex)logic.SetStartState(item, action);
if (action.Index > _actionIndex)logic.SetStartState(data, item, action);
}
}
}
@ -147,11 +254,24 @@ namespace TH1_Logic.Comic
public void Clear()
{
if (_comicMono) Object.DestroyImmediate(_comicMono.gameObject);
_comicData = null;
_comicItems.Clear();
_comicMono = null;
_state = ComicState.None;
if (_comicSheet != null)
{
foreach (var data in _comicSheet.ComicDatas) ClearComicData(data);
}
if (_comicData != null) ClearComicData(_comicData);
}
public void ClearComicData(ComicData data)
{
if(data.Mono) Object.DestroyImmediate(data.Mono.gameObject);
foreach (var kv in data.ComicItems)
{
if (kv.Value) Object.DestroyImmediate(kv.Value.gameObject);
}
data.Mono = null;
data.ComicItems.Clear();
}
}
}

View File

@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Numerics;
using Logic.Multilingual;
using MemoryPack;
@ -83,6 +84,13 @@ namespace TH1_Logic.Comic
public ComicBackground Background;
public List<ComicSubItem> SubItems;
public List<ComicAction> Actions;
[MemoryPackIgnore]
public ComicMono Mono;
[MemoryPackIgnore]
public Dictionary<uint, ComicItemMono> ComicItems = new Dictionary<uint, ComicItemMono>();
[MemoryPackIgnore] public ComicAction FadeInAction;
[MemoryPackIgnore] public ComicAction FadeOutAction;
[MemoryPackConstructor]
@ -92,7 +100,21 @@ namespace TH1_Logic.Comic
SubItems = new List<ComicSubItem>();
Actions = new List<ComicAction>();
}
public void SaveItemsMono()
{
foreach (var item in SubItems)
{
item.SaveItemMonoInfo();
}
}
public void ApplyToMono()
{
var backgroundImage = ComicManager.Instance.GetImage(Background.ImageName);
if (backgroundImage) Mono.BackgroundImage.sprite = backgroundImage;
}
public void AddSubItem()
{
var item = new ComicSubItem();
@ -121,7 +143,7 @@ namespace TH1_Logic.Comic
Actions.Remove(action);
}
public ComicSubItem GetSubItemById(uint id)
public ComicSubItem GetSubItemById(int id)
{
foreach (var item in SubItems)
{
@ -138,6 +160,28 @@ namespace TH1_Logic.Comic
}
return null;
}
public void InitFadeInAction(ComicActionType fadeInType)
{
FadeInAction = new ComicAction
{
ActionType = fadeInType,
TargetId = -1,
Index = 0,
Duration = 1f,
};
}
public void InitFadeOutAction(ComicActionType fadeOutType)
{
FadeOutAction = new ComicAction
{
ActionType = fadeOutType,
TargetId = -1,
Index = Actions.Count,
Duration = 1f,
};
}
}
@ -161,7 +205,7 @@ namespace TH1_Logic.Comic
[MemoryPackable]
public partial class ComicSubItem
{
public uint Id;
public int Id;
public ComicSubItemType ItemType;
public float PositionX;
public float PositionY;
@ -169,6 +213,9 @@ namespace TH1_Logic.Comic
public float Height;
public string ImageName;
public string Content;
[MemoryPackIgnore]
public ComicItemMono Mono;
public ComicSubItem()
{
@ -182,20 +229,32 @@ namespace TH1_Logic.Comic
Content = string.Empty;
}
public void SaveItemMonoInfo()
{
PositionX = Mono.ItemRect.anchoredPosition.x;
PositionY = Mono.ItemRect.anchoredPosition.y;
Width = Mono.ItemRect.sizeDelta.x;
Height = Mono.ItemRect.sizeDelta.y;
}
public void ApplyToItemMono(ComicItemMono mono)
public void ApplyToItemMono()
{
if (ItemType == ComicSubItemType.Image)
{
var image = ComicManager.Instance.GetImage(ImageName);
if (image) mono.ItemImage.sprite = image;
if (image) Mono.ItemImage.sprite = image;
var pos = new UnityEngine.Vector2(PositionX, PositionY);
Mono.ItemRect.anchoredPosition = pos;
Mono.ItemRect.sizeDelta = new UnityEngine.Vector2(Width, Height);
}
if (ItemType == ComicSubItemType.Dialog)
{
var dialogImage = ComicManager.Instance.GetImage(ImageName);
if (dialogImage) mono.DialogImage.sprite = dialogImage;
MultilingualManager.Instance.SetUIText(mono.TextMono, Content);
if (dialogImage) Mono.DialogImage.sprite = dialogImage;
MultilingualManager.Instance.SetUIText(Mono.TextMono, Content);
var pos = new UnityEngine.Vector2(PositionX, PositionY);
Mono.ItemRect.anchoredPosition = pos;
}
}
}

View File

@ -15,6 +15,7 @@ namespace TH1_Logic.Comic
{
public class ComicItemMono : MonoBehaviour
{
public RectTransform ItemRect;
public TextMeshProUGUI TextMono;
public Image DialogImage;
public Image ItemImage;

View File

@ -21,15 +21,17 @@ namespace TH1_Logic.Comic
public static ComicManager Instance = new ComicManager();
private ComicAsset _asset;
private ImageMapData _imageMap;
public ComicAsset Asset => _asset;
public ImageMapData ImageMap => _imageMap;
private GameObject _comicPrefab;
private GameObject _comicInstance;
private ComicMono _comicMono;
private Dictionary<string, Sprite> _comicTextures = new Dictionary<string, Sprite>();
private Dictionary<ComicActionType, Vector2> _actionPos = new Dictionary<ComicActionType, Vector2>();
private ComicControl _comicControl;
private Dictionary<string, Sprite> _comicSprites = new Dictionary<string, Sprite>();
private ComicControl _comicControl = new ComicControl();
public ComicControl ComicControl => _comicControl;
public void InitComic(string comicName, GameObject root)
{
Refresh();
@ -44,9 +46,8 @@ namespace TH1_Logic.Comic
LogSystem.LogError($"[ComicManager] PlayComic failed: ComicSheet {comicName} has no ComicData");
return;
}
var comicData = sheet.ComicDatas[0];
_comicControl ??= new ComicControl();
_comicControl.Init(comicData, root);
_comicControl.Init(sheet, root);
}
public void Next()
@ -54,18 +55,16 @@ namespace TH1_Logic.Comic
_comicControl?.Next();
}
public void Update()
{
_comicControl?.Update(Time.deltaTime);
}
public void Refresh()
{
_asset ??= LoadComicAsset() ?? new ComicAsset();
_actionPos.Clear();
_actionPos[ComicActionType.SlideInLeft] = new Vector2(-1, 0);
_actionPos[ComicActionType.SlideOutLeft] = new Vector2(-1, 0);
_actionPos[ComicActionType.SlideInRight] = new Vector2(1, 0);
_actionPos[ComicActionType.SlideOutRight] = new Vector2(1, 0);
_actionPos[ComicActionType.SlideInUp] = new Vector2(0, 1);
_actionPos[ComicActionType.SlideOutUp] = new Vector2(0, 1);
_actionPos[ComicActionType.SlideInDown] = new Vector2(0, -1);
_actionPos[ComicActionType.SlideOutDown] = new Vector2(0, -1);
_imageMap ??= LoadImageMap() ?? new ImageMapData();
_comicControl ??= new ComicControl();
}
public void AddComicSheet(string name)
@ -76,22 +75,25 @@ namespace TH1_Logic.Comic
public Sprite GetImage(string name)
{
if (_comicTextures.TryGetValue(name, out var image)) return image;
if (_comicSprites.TryGetValue(name, out var image)) return image;
var texture = LoadImage(name);
if (texture) _comicTextures.Add(name, texture);
if (texture) _comicSprites[name] = texture;
else LogSystem.LogError($"[ComicManager] GetImage failed: {name}");
return texture;
}
public Sprite LoadImage(string name)
{
var texture = Resources.Load<Sprite>($"Comic/Image/{name}");
if (!texture) LogSystem.LogError($"[ComicManager] LoadImage failed: {name}");
return texture;
var path = _imageMap?.GetImageMap(name);
if (string.IsNullOrEmpty(path)) return null;
var sprite = Resources.Load<Sprite>(path);
if (!sprite) LogSystem.LogError($"[ComicManager] LoadImage failed: {path}");
return sprite;
}
public GameObject LoadPrefab(string name)
{
var prefab = Resources.Load<GameObject>($"Comic/Prefab/{name}");
var prefab = Resources.Load<GameObject>($"ArtResources/Comic/Prefab/{name}");
if (!prefab) LogSystem.LogError($"[ComicManager] LoadPrefab failed: {name}");
return prefab;
}
@ -119,6 +121,54 @@ namespace TH1_Logic.Comic
}
}
public ImageMapData LoadImageMap()
{
try
{
string resourcePath = $"Comic/ImageMap";
TextAsset textAsset = Resources.Load<TextAsset>(resourcePath);
if (textAsset == null)
{
LogSystem.LogWarning($"LoadImageMap: 未找到资源 {resourcePath}");
return null;
}
ImageMapData imageMap = MemoryPackSerializer.Deserialize<ImageMapData>(textAsset.bytes);
LogSystem.LogInfo($"LoadImageMap: 加载成功");
return imageMap;
}
catch (System.Exception e)
{
LogSystem.LogWarning($"LoadImageMap: 加载失败 - {e.Message}");
return null;
}
}
public void SaveImageMapData()
{
#if UNITY_EDITOR
if (_imageMap == null) return;
try
{
// 确保文件夹存在
string folderPath = Path.Combine(Application.dataPath, "Resources", "Comic");
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string filePath = Path.Combine(folderPath, $"IamgeMap.bytes");
byte[] bytes = MemoryPackSerializer.Serialize(_imageMap);
File.WriteAllBytes(filePath, bytes);
// 刷新 AssetDatabase
UnityEditor.AssetDatabase.Refresh();
LogSystem.LogInfo($"SaveImageMapData: SaveImageMapData 保存成功,路径: {filePath}");
}
catch (System.Exception e)
{
LogSystem.LogWarning($"SaveImageMapData: 保存失败 - {e.Message}");
}
#endif
}
public void SaveComicData()
{
#if UNITY_EDITOR
@ -144,11 +194,52 @@ namespace TH1_Logic.Comic
#endif
}
public Vector2 GetActionPos(ComicActionType actionType)
public void RefreshImageData()
{
if (_actionPos.TryGetValue(actionType, out var pos)) return pos;
return Vector2.Zero;
#if UNITY_EDITOR
Refresh();
_imageMap.ImageMap.Clear();
// 获取 Resources/Comic 文件夹的物理路径
string comicPath = Path.Combine(Application.dataPath, "Resources", "ArtResources/Comic");
if (!Directory.Exists(comicPath))
{
LogSystem.LogWarning($"RefreshImageData: 未找到文件夹 {comicPath}");
return;
}
// 递归搜索所有图片文件
string[] imageExtensions = new[] { "*.png", "*.jpg", "*.jpeg" };
List<string> allImageFiles = new List<string>();
foreach (var extension in imageExtensions)
{
var files = Directory.GetFiles(comicPath, extension, SearchOption.AllDirectories);
allImageFiles.AddRange(files);
}
// 添加到 ImageMap
foreach (var filePath in allImageFiles)
{
// 获取 Resources 文件夹路径
string resourcesPath = Path.Combine(Application.dataPath, "Resources");
// 转换为相对于 Resources 的路径
string relativePath = filePath.Replace(resourcesPath, "").TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
// 移除扩展名
string imageKey = Path.GetFileNameWithoutExtension(Path.GetFileName(relativePath));
// 转换为 Resources.Load 使用的路径格式(移除扩展名)
string resourcePath = Path.ChangeExtension(relativePath, null).Replace(Path.DirectorySeparatorChar, '/');
_imageMap.ImageMap.TryAdd(imageKey, resourcePath);
}
LogSystem.LogInfo($"RefreshImageData: 已刷新 {_imageMap.ImageMap.Count} 张图片");
SaveImageMapData();
#endif
}
}
}

View File

@ -17,5 +17,6 @@ namespace TH1_Logic.Comic
public Image BackgroundImage;
public Image BlackImage;
public Transform ItemRoot;
public RectTransform Rect;
}
}

View File

@ -0,0 +1,39 @@
/*
* @Author:
* @Description:
* @Date: 20260126 16:01:27
* @Modify:
*/
using System.Collections.Generic;
using System.Numerics;
using Logic.Multilingual;
using MemoryPack;
namespace TH1_Logic.Comic
{
[MemoryPackable]
public partial class ImageMapData
{
public Dictionary<string, string> ImageMap;
[MemoryPackConstructor]
public ImageMapData()
{
ImageMap = new Dictionary<string, string>();
}
public void AddImageMap(string key, string value)
{
ImageMap[key] = value;
}
public string GetImageMap(string key)
{
return ImageMap.GetValueOrDefault(key);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f4be899888e4bb2b18eca874667a4ca
timeCreated: 1770261083

View File

@ -36,6 +36,9 @@ namespace Logic.Editor
private string _selectedName;
private List<string> _itemIdList;
private bool _isPlaying = false;
private GameObject _root;
private string _newName = "comic";
@ -48,13 +51,40 @@ namespace Logic.Editor
window.Show();
}
private void OnEnable()
protected virtual void OnEnable()
{
EditorApplication.update += OnEditorUpdate;
RefreshStrList();
}
private void OnDisable()
{
EditorApplication.update -= OnEditorUpdate;
Refresh();
// 从后往前删除,避免索引变化
for (int i = _root.transform.childCount - 1; i >= 0; i--)
{
DestroyImmediate(_root.transform.GetChild(i).gameObject);
}
}
private void OnEditorUpdate()
{
// 每帧刷新窗口
Repaint();
}
private void Refresh()
{
if (!_root) _root = GameObject.Find($"UICanvas/Comic");
}
private void OnGUI()
{
Refresh();
ComicManager.Instance.Refresh();
if(_isPlaying) ComicManager.Instance.ComicControl.Update();
if (_redBoxStyle == null)
{
_redBoxStyle = InspectorUtils.GetHelpBoxStyle();
@ -83,19 +113,25 @@ namespace Logic.Editor
if (InspectorUtils.InspectorButtonWithTextWidth("保存"))
{
ComicManager.Instance.SaveComicData();
}
if (InspectorUtils.InspectorButtonWithTextWidth("检索图片库并保存"))
{
ComicManager.Instance.RefreshImageData();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (ComicManager.Instance.ComicControl.State == ComicState.Playing)
if (_isPlaying)
{
var actionIndex = ComicManager.Instance.ComicControl.ActionIndex;
var data = ComicManager.Instance.ComicControl.ComicData;
var maxIndex = ComicManager.Instance.ComicControl.MaxIndex;
var sheet = ComicManager.Instance.ComicControl.ComicSheet;
var progress = ComicManager.Instance.ComicControl.Progress;
InspectorUtils.InspectorTextWidthRich($"<b> 播放中 请勿移动或保存 </b>");
InspectorUtils.InspectorTextWidthRich($"<b> 漫画:{data} </b>");
InspectorUtils.InspectorTextWidthRich($"<b> Action : {actionIndex} / {data.Actions.Count}</b>");
InspectorUtils.InspectorTextWidthRich($"<b> 进度 : {progress} / {data.Actions[actionIndex].Duration}</b>");
var duration = ComicManager.Instance.ComicControl.Duration;
InspectorUtils.InspectorTextWidthRich($"<b> 播放中</b>");
InspectorUtils.InspectorTextWidthRich($"<b> 漫画:{sheet.Name} </b>");
InspectorUtils.InspectorTextWidthRich($"<b> Action : {actionIndex} / {maxIndex}</b>");
InspectorUtils.InspectorTextWidthRich($"<b> 进度 : {progress} / {duration}</b>");
}
EditorGUILayout.EndHorizontal();
@ -117,20 +153,50 @@ namespace Logic.Editor
comicSheet.AddComicData();
EditorGUILayout.EndHorizontal();
int deleteIndex = -1;
int upIndex = -1;
int downIndex = -1;
for (int i = 0; i < comicSheet.ComicDatas.Count; i++)
EditorGUILayout.BeginHorizontal();
if (_isPlaying) InspectorUtils.InspectorTextWidthRich($"播放中, 请勿操作 GameObject");
else InspectorUtils.InspectorTextWidthRich($"编辑中, 可以操作 GameObject");
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth($"播放"))
{
OnGUIComicData(comicSheet.ComicDatas[i], i, out bool delete, out bool up, out bool down);
if (up) upIndex = i;
if (down) downIndex = i;
if (delete) deleteIndex = i;
EditorGUILayout.Space();
// 从后往前删除,避免索引变化
for (int i = _root.transform.childCount - 1; i >= 0; i--)
{
DestroyImmediate(_root.transform.GetChild(i).gameObject);
}
ComicManager.Instance.InitComic(comicSheet.Name, _root);
_isPlaying = true;
}
if (_isPlaying && InspectorUtils.InspectorButtonWithTextWidth($"模拟点击"))
{
ComicManager.Instance.Next();
}
if (_isPlaying && InspectorUtils.InspectorButtonWithTextWidth($"停止播放"))
{
_isPlaying = false;
ComicManager.Instance.ComicControl.Clear();
}
EditorGUILayout.EndHorizontal();
if (!_isPlaying)
{
int deleteIndex = -1;
int upIndex = -1;
int downIndex = -1;
for (int i = 0; i < comicSheet.ComicDatas.Count; i++)
{
OnGUIComicData(comicSheet.ComicDatas[i], i, out bool delete, out bool up, out bool down);
if (up) upIndex = i;
if (down) downIndex = i;
if (delete) deleteIndex = i;
EditorGUILayout.Space();
}
if (deleteIndex >= 0) comicSheet.ComicDatas.RemoveAt(deleteIndex);
else if (upIndex >= 0) comicSheet.MoveComicData(comicSheet.ComicDatas[upIndex], -1);
else if (downIndex >= 0) comicSheet.MoveComicData(comicSheet.ComicDatas[downIndex], 1);
}
if (deleteIndex >= 0) comicSheet.ComicDatas.RemoveAt(deleteIndex);
else if (upIndex >= 0) comicSheet.MoveComicData(comicSheet.ComicDatas[upIndex], -1);
else if (downIndex >= 0) comicSheet.MoveComicData(comicSheet.ComicDatas[downIndex], 1);
}
EditorGUILayout.EndScrollView();
}
@ -141,15 +207,6 @@ namespace Logic.Editor
down = false;
isDelete = false;
EditorGUILayout.BeginVertical(_whiteBoxStyle, GUILayout.Width(500));
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth($"预览"))
{
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich($"第 {id + 1} 页");
@ -158,6 +215,19 @@ namespace Logic.Editor
if (InspectorUtils.InspectorButtonWithTextWidth($"x")) isDelete = true;
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth($"预览并编辑此页"))
{
// 从后往前删除,避免索引变化
for (int i = _root.transform.childCount - 1; i >= 0; i--)
{
DestroyImmediate(_root.transform.GetChild(i).gameObject);
}
ComicManager.Instance.ComicControl.PreviewComicData(data, _root);
}
if (data.Mono && InspectorUtils.InspectorButtonWithTextWidth($"保存此页")) data.SaveItemsMono();
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich("底图:");
var index = GetIndexInStrList(data.Background.ImageName, _bigImageList);
@ -166,6 +236,11 @@ namespace Logic.Editor
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth($"添加Item")) data.AddSubItem();
EditorGUILayout.EndHorizontal();
// Items
EditorGUILayout.BeginVertical(_whiteBoxStyle);
var deleteIndex = -1;
@ -175,13 +250,16 @@ namespace Logic.Editor
if (delete) deleteIndex = i;
EditorGUILayout.Space();
}
if (deleteIndex >= 0) data.RemoveSubItem(data.SubItems[deleteIndex]);
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
// Actions
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth($"添加Action")) data.AddAction();
EditorGUILayout.EndHorizontal();
_itemIdList ??= new List<string>();
_itemIdList.Clear();
foreach (var item in data.SubItems) _itemIdList.Add($"{item.Id}");
@ -194,6 +272,8 @@ namespace Logic.Editor
EditorGUILayout.Space();
}
if (deleteIndex >= 0) data.RemoveAction(data.Actions[deleteIndex]);
EditorGUILayout.EndVertical();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
@ -231,7 +311,7 @@ namespace Logic.Editor
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich($"对话: ");
InspectorUtils.InspectorTextWidthRich($"对话 ID: ");
item.Content = EditorGUILayout.TextField(item.Content, GUILayout.Width(300));
EditorGUILayout.EndHorizontal();
}
@ -249,7 +329,7 @@ namespace Logic.Editor
InspectorUtils.InspectorTextWidthRich($"目标 Item");
var index = GetIndexInStrList(action.TargetId.ToString(), _itemIdList);
index = EditorGUILayout.Popup(index, _itemIdList.ToArray(), GUILayout.Width(300));
if (_itemIdList.Count != 0) action.TargetId = uint.Parse(_itemIdList[index]);
if (_itemIdList.Count != 0) action.TargetId = int.Parse(_itemIdList[index]);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
@ -267,7 +347,7 @@ namespace Logic.Editor
{
for (int i = 0; i < list.Count; i++)
{
if (_comicList[i] == name) return i;
if (list[i] == str) return i;
}
return 0;
}
@ -317,7 +397,7 @@ namespace Logic.Editor
_dialogList ??= new List<string>();
_dialogList.Clear();
folderPath = "Assets/Resources/ArtResources/Comic/Image";
folderPath = "Assets/Resources/ArtResources/Comic/Dialog";
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
files = Directory.GetFiles(folderPath, "*.png");
foreach (string file in files)

View File

@ -498,7 +498,7 @@ namespace TH1_UI.View.Outside
};
Main.Instance.MapConfig = MatchConfigManager.Instance.GetMatchConfig(2);
Main.Instance.MapConfig.ChangeByMapConfig(MatchConfigManager.Instance.GetMatchConfig(2));
Main.Instance.MapConfig.Width = mapSize;
Main.Instance.MapConfig.Height = mapSize;
Main.Instance.MapConfig.PlayerCount = playerCount;

View File

@ -243,8 +243,7 @@ namespace TH1_UI.View.Outside
};
// game mode perfect => 3 domination => 2
Main.Instance.MapConfig = MatchConfigManager.Instance.GetMatchConfig(2);
Main.Instance.MapConfig.ChangeByMapConfig(MatchConfigManager.Instance.GetMatchConfig(2));
Main.Instance.MapConfig.Width = mapSize;
Main.Instance.MapConfig.Height = mapSize;
Main.Instance.MapConfig.PlayerCount = playerCount;