Ver.0.3.0.33

This commit is contained in:
2025-07-08 08:32:46 +00:00
parent 99f4dd67c2
commit 0ad5e29917
6831 changed files with 695623 additions and 234455 deletions
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2b4d826b979c4f20acfd79e163a5d425
timeCreated: 1748337675
@@ -0,0 +1,57 @@
using System;
using UnityEngine.Events;
using UnityEngine.UI;
namespace AibisDream
{
public class BaseButton : Button
{
public SelectionType CurSelectionState => TransStateToType(currentSelectionState);
public UnityEvent<SelectionType, bool> onStateTransition = new();
protected override void DoStateTransition(SelectionState state, bool instant)
{
if (!gameObject.activeInHierarchy)
return;
onStateTransition?.Invoke(TransStateToType(state), instant);
}
protected static SelectionType TransStateToType(SelectionState state)
{
return Enum.Parse<SelectionType>(state.ToString());
}
}
/// <summary>
/// 因为作用域问题把枚举转出来用
/// </summary>
public enum SelectionType
{
/// <summary>
/// The UI object can be selected.
/// </summary>
Normal,
/// <summary>
/// The UI object is highlighted.
/// </summary>
Highlighted,
/// <summary>
/// The UI object is pressed.
/// </summary>
Pressed,
/// <summary>
/// The UI object is selected
/// </summary>
Selected,
/// <summary>
/// The UI object cannot be selected.
/// </summary>
Disabled
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5702aa38bfd4746aecc799b153aab91
timeCreated: 1748343214
@@ -0,0 +1,59 @@
using System;
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization.Components;
using UnityEngine.UI;
namespace AibisDream
{
[RequireComponent(typeof(Button))]
public class BoolButton : MonoBehaviour
{
private Image _buttonImage;
private LocalizeStringEvent _stringEvent;
private Button _button;
public BoolButtonData data;
public Func<bool> getBool;
public UnityEvent OnClick
{
get
{
if (_button == null) _button = GetComponent<Button>();
return _button.onClick;
}
}
public void Awake()
{
_stringEvent = GetComponentInChildren<LocalizeStringEvent>();
_buttonImage = GetComponentInChildren<Image>();
// 监听按钮点击
_button = GetComponent<Button>();
OnClick.AddListener(() => _ = CommonUtil.Delay(100, AfterClick));
}
private void AfterClick()
{
if (_buttonImage)
{
_buttonImage.sprite = getBool.Invoke() ? data.trueSprite : data.falseSprite;
}
if (_stringEvent)
{
_stringEvent.SetEntry(getBool.Invoke() ? data.trueKey : data.falseKey);
}
}
}
[Serializable]
public struct BoolButtonData
{
public string trueKey;
public Sprite trueSprite;
public string falseKey;
public Sprite falseSprite;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9ccf36d0564d46b98327fbcbfb03096b
timeCreated: 1749474015
@@ -0,0 +1,55 @@
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class ColorTintButton : Button
{
[SerializeField] private Graphic[] insideGraphics;
[SerializeField] private ColorBlock insideColorConfig = ColorBlock.defaultColorBlock;
[SerializeField] private Graphic[] backGraphics;
[SerializeField] private ColorBlock backColorConfig = ColorBlock.defaultColorBlock;
protected override void DoStateTransition(SelectionState state, bool instant)
{
if (!gameObject.activeInHierarchy)
return;
var insideColor = state switch
{
SelectionState.Normal => insideColorConfig.normalColor,
SelectionState.Highlighted => insideColorConfig.highlightedColor,
SelectionState.Pressed => insideColorConfig.pressedColor,
SelectionState.Selected => insideColorConfig.selectedColor,
SelectionState.Disabled => insideColorConfig.disabledColor,
_ => Color.black
};
StartColorTween(insideGraphics, insideColor * insideColorConfig.colorMultiplier, instant);
var backColor = state switch
{
SelectionState.Normal => backColorConfig.normalColor,
SelectionState.Highlighted => backColorConfig.highlightedColor,
SelectionState.Pressed => backColorConfig.pressedColor,
SelectionState.Selected => backColorConfig.selectedColor,
SelectionState.Disabled => backColorConfig.disabledColor,
_ => Color.black
};
StartColorTween(backGraphics, backColor * insideColorConfig.colorMultiplier, instant);
}
private void StartColorTween(Graphic[] graphics, Color targetColor, bool instant)
{
if (graphics is { Length: > 0 })
{
foreach (var graphic in graphics)
{
graphic?.CrossFadeColor(targetColor, instant ? 0f : insideColorConfig.fadeDuration, true, true);
}
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 566501c4f7a049a5af0114ca8bab5c72
timeCreated: 1748344650
+92 -31
View File
@@ -1,34 +1,41 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace AibisDream
{
public class CursorManager : MonoBehaviour
public class CursorManager : Singleton<CursorManager>
{
private const float DelayTime = 0.1f;
[Header("指针图片")] public Sprite defaultCursor;
public Sprite nextTalk, talking, option, interactive, holding, disable, eye;
public Sprite nextTalk, talking, option, interactive, holding, disable;
private Image _cursor;
private GraphicRaycaster _raycaster;
private Sprite _curCursor;
private CursorState _stateCache;
#region
private Coroutine _switchCoroutine;
private CursorState _curState = CursorState.Default;
private bool _isTalking;
[HideInInspector] public bool isInMenu;
private bool _isInGame;
#endregion
// 卸载时注销事件
private readonly List<IUnRegister> _unRegisters = new();
public void Awake()
private void Start()
{
InitRefs();
InitCursor();
@@ -59,14 +66,54 @@ namespace AibisDream
private void InitRefs()
{
_cursor = transform.Find("Cursor").GetComponent<Image>();
_raycaster = UIManager.Instance.Canvas.GetComponent<GraphicRaycaster>();
}
private void RegisterEvent()
{
// 此处监听所有可能对鼠标状态产生影响的事件
RegisterGameEvent();
RegisterDialogEvent();
RegisterTriggerEvent();
RegisterMenu();
}
private void RegisterGameEvent()
{
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.GameStart, OnGameStart));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, OnGameQuit));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.PauseGame, OnPauseGame));
_unRegisters.Add(EnumEventSystem.Global.Register(GameLoopEnum.UnPauseGame, OnUnPauseGame));
}
private void OnGameStart()
{
_isInGame = true;
}
private void OnUnPauseGame()
{
_curState = _stateCache;
_stateCache = CursorState.Default;
_isInGame = true;
}
private void OnPauseGame()
{
_stateCache = _curState;
_curState = CursorState.Default;
_isInGame = false;
}
private void OnGameQuit()
{
_curCursor = defaultCursor;
_curState = CursorState.Default;
_stateCache = CursorState.Default;
_isInGame = false;
}
private void RegisterDialogEvent()
@@ -98,22 +145,48 @@ namespace AibisDream
EnumEventSystem.Global.Register<TriggerEnum, IInteraction>(TriggerEnum.PointerUp, OnPointerUp));
}
private void RegisterMenu()
{
_unRegisters.Add(EnumEventSystem.Global.Register<EventEnum, bool>(EventEnum.Menu, OnMenuChange));
}
private void Update()
{
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space))
UpdateCursor();
HandleDialog();
}
private void UpdateCursor()
{
// 再判断是不是浮在可交互物上
_cursor.sprite = !_isInGame || IsOverSelected() ? defaultCursor : _curCursor;
}
private void HandleDialog()
{
if (!_isInGame) return;
if (!Input.GetMouseButtonDown(0) && !Input.GetKeyDown(KeyCode.Space)) return;
// 控制对话
if (_isTalking)
{
if (_isTalking && !isInMenu)
{
DialogController.Instance.JumpLine();
}
DialogController.Instance.JumpLine();
}
}
private bool IsOverSelected()
{
if (!EventSystem.current.IsPointerOverGameObject())
{
return false;
}
var eventData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
var results = new List<RaycastResult>();
_raycaster.Raycast(eventData, results);
return results.Count > 0 && results.Any(result => result.gameObject.CompareTag("Selectable"));
}
private void LateUpdate()
{
// // 将虚拟指针与鼠标位置同步
@@ -139,7 +212,7 @@ namespace AibisDream
_switchCoroutine = StartCoroutine(DelayAction(() =>
{
_isTalking = false;
_cursor.sprite = defaultCursor;
_curCursor = defaultCursor;
}));
}
@@ -155,7 +228,7 @@ namespace AibisDream
_switchCoroutine = StartCoroutine(DelayAction(() =>
{
_isTalking = false;
_cursor.sprite = defaultCursor;
_curCursor = defaultCursor;
}));
}
@@ -212,17 +285,6 @@ namespace AibisDream
SwitchCursor(EventSystemEx.Instance.holdingObj == target.GetGameObject() ? interactive : defaultCursor);
}
}
#endregion
#region
private void OnMenuChange(bool isMenuOpen)
{
isInMenu = isMenuOpen;
}
#endregion
@@ -235,7 +297,7 @@ namespace AibisDream
private void SwitchCursor(Sprite sprite)
{
StopDelayCursor();
_cursor.sprite = sprite;
_curCursor = sprite;
}
private void StopDelayCursor()
@@ -259,7 +321,6 @@ namespace AibisDream
public enum CursorState
{
Default,
Interactive,
Eye
Interactive
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d9cb39e4c7764dcf8f99fe429a8edc19
timeCreated: 1749038925
@@ -0,0 +1,175 @@
using System;
using System.Text.RegularExpressions;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI.Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class Bubble : MonoBehaviour
{
private TypewriterCore _typewriter;
private TMP_Text _actorName;
private TMP_Text _lineText;
private LayoutElement _layoutElement;
private LayoutGroup _layoutGroup;
private RectTransform _rect;
private Image _bubbleImage;
#region
[SerializeField] public ActorRole role;
[SerializeField] public int idx;
[SerializeField] private int maxWidth;
[SerializeField] private int minWidth;
#endregion
public event Action<Bubble> OnDisposed;
public bool IsShowingText => _typewriter.isShowingText;
public void LoadConfig(BubbleSlotData data)
{
InitRefs();
role = data.actorRole;
idx = data.idx;
maxWidth = data.maxWidth;
minWidth = data.minWidth;
var rect = transform as RectTransform;
rect.localPosition = UIManager.GetDialogUIPos(data.slotPosition);
// 设置style
SetStyle(data.bubbleStyle, data.pivotType);
}
private void SetStyle(BubbleStyle bubbleStyle, PivotType pivotType)
{
_bubbleImage.color = bubbleStyle.imageColor;
// padding内容
_layoutGroup.padding = bubbleStyle.BubblePadding;
_lineText.margin = bubbleStyle.linePadding;
_lineText.fontSize = bubbleStyle.lineFontSize;
_actorName.margin = bubbleStyle.actorPadding;
_actorName.fontSize = bubbleStyle.actorFontSize;
// 是否展示名称
_actorName.gameObject.SetActive(bubbleStyle.hasActorName);
// 锚点相关
_rect.pivot = CommonUtil.GetPivotByType(pivotType);
var spritePath = bubbleStyle.bubbleSpriteAddress.EndsWith("]")
? $"{bubbleStyle.bubbleSpriteAddress}"
: $"{bubbleStyle.bubbleSpriteAddress}[{pivotType.ToString()}]";
_bubbleImage.sprite = ResourceKit.LoadAssetSync<Sprite>(spritePath);
}
private void InitRefs()
{
_typewriter = GetComponentInChildren<TypewriterCore>();
_actorName = transform.Find("名称").GetComponent<TMP_Text>();
_typewriter.onTextShowed.RemoveAllListeners();
_typewriter.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
// 获取内容文字
_lineText = _typewriter.GetComponent<TMP_Text>();
_layoutElement = _typewriter.GetComponent<LayoutElement>();
// 气泡自身
_layoutGroup = GetComponent<LayoutGroup>();
_bubbleImage = GetComponent<Image>();
_rect = _bubbleImage.rectTransform;
}
public void ShowActorName(CharacterVo characterVo)
{
if (_actorName == null) return;
_actorName.text = string.IsNullOrEmpty(characterVo.GetActorName())
? string.Empty
: characterVo.GetActorName();
}
public void ShowLine(string line)
{
_typewriter.TextAnimator.SetText("");
gameObject.SetActive(true);
HandleLayout(line);
_typewriter.ShowText(line);
}
public void SkipLine()
{
if (_typewriter.isShowingText)
{
_typewriter.SkipTypewriter();
}
}
public void Hide()
{
gameObject.SetActive(false);
}
public void Dispose()
{
Hide();
OnDisposed?.Invoke(this);
OnDisposed = null;
}
private void HandleLayout(string line)
{
// 先去除富文本标签
line = Regex.Replace(line.Replace("<br>", "\n"), "[<|{].*?[>|}]", string.Empty);
var width = DialogCanvasManager.Instance.EstimateTextWidth(line, _lineText.fontSize);
if (width > maxWidth)
{
_layoutElement.preferredWidth = maxWidth;
}
else
{
_layoutElement.preferredWidth = -1;
}
_layoutElement.minWidth = minWidth;
LayoutRebuilder.ForceRebuildLayoutImmediate(_rect);
}
#if UNITY_EDITOR
[Header("测试参数")] public int testMinWidth;
public int testMaxWidth;
public BubbleStyle testBubbleStyle;
public PivotType testPivotType;
public void LoadStyle()
{
InitRefs();
SetStyle(testBubbleStyle, testPivotType);
_layoutElement.minWidth = testMinWidth;
_layoutElement.preferredWidth = testMaxWidth;
}
public void SaveStyle()
{
if (!testBubbleStyle) return;
InitRefs();
testBubbleStyle.linePadding = _lineText.margin;
testBubbleStyle.lineFontSize = _lineText.fontSize;
testBubbleStyle.actorPadding = _actorName.margin;
testBubbleStyle.actorFontSize = _actorName.fontSize;
testBubbleStyle.BubblePadding = _layoutGroup.padding;
testBubbleStyle.hasActorName = _actorName.gameObject.activeSelf;
}
#endif
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6adb9d7cc075457a8fece1b14ca4c429
timeCreated: 1749022700
@@ -0,0 +1,37 @@
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using UnityEngine;
namespace AibisDream
{
public class BubbleFactory
{
private readonly SimpleObjectPool<Bubble> _pool;
private readonly GameObject _bubblePrefab;
private readonly Transform _bubbleRoot;
public BubbleFactory(Transform bubbleRoot)
{
_bubbleRoot = bubbleRoot;
_bubblePrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.BubblePrefab);
_pool = new SimpleObjectPool<Bubble>(InstantiateBubble);
}
public Bubble Create(BubbleSlotData data)
{
var bubble = _pool.Allocate();
bubble.OnDisposed += o => _pool.Recycle(o);
bubble.LoadConfig(data);
bubble.Hide();
return bubble;
}
private Bubble InstantiateBubble()
{
return Object.Instantiate(_bubblePrefab, _bubbleRoot).GetComponent<Bubble>();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da7e7fe867834c0aa077caf6aba8fd93
timeCreated: 1749123699
@@ -0,0 +1,215 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
namespace AibisDream
{
public class BubbleGroup : Singleton<BubbleGroup>, IDialogView
{
private BubbleOption[] _options;
private Dictionary<ActorRole, Bubble[]> _bubbleDict;
public DialogViewType CurDialogType { get; private set; }
private BubbleFactory _bubbleFactory;
private SimpleObjectPool<Bubble> _bubblePool;
private SimpleObjectPool<BubbleOption> _optionPool;
#region
private Action _nextStep;
private Bubble _curBubble;
private IUnRegister _unRegister;
#endregion
#region
public override void OnSingletonInit()
{
// 注册泡泡
_unRegister =
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
_ => HideOptions());
// 工厂
_bubbleFactory = new BubbleFactory(transform.Find("Bubbles"));
// 加载选项
InitOptions();
}
private void Start()
{
HideDialog();
}
public override void OnSingletonDestroy()
{
_unRegister.UnRegister();
}
public void LoadBubbles(BubbleSlotGroupData groupData)
{
CurDialogType = groupData.dialogViewType;
// 回收旧泡泡
foreach (var oldBubble in _bubbleDict.Values.SelectMany(item => item))
{
oldBubble.Dispose();
}
// 加载新泡泡
_bubbleDict = groupData.bubbleSlots
.Select(item => _bubbleFactory.Create(item))
.GroupBy(item => item.role)
.ToDictionary(group => group.Key, group => group.ToArray());
// 更新选项的位置
if (groupData.bubbleOptionSlots is { Length: 0 })
{
return;
}
foreach (var optionSlotData in groupData.bubbleOptionSlots)
{
if (optionSlotData.optionIdx >= _options.Length) continue;
_options[optionSlotData.optionIdx].LoadData(optionSlotData);
}
}
private void InitOptions()
{
_options = transform.Find("Options")
.GetComponentsInChildren<BubbleOption>(true)
.OrderBy(item => item.optionIdx)
.ToArray();
_bubbleDict = new Dictionary<ActorRole, Bubble[]>();
}
#endregion
#region
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
gameObject.SetActive(true);
if (TryGetBubble(character.role, character.bubbleIdx, out var bubble))
{
bubble.ShowActorName(character);
bubble.ShowLine(dialogLine);
// 将非选定的Bubble隐藏
HideDialog(bubble);
}
else
{
Debug.LogWarning($"{character.GetActorName()}的Role没有对应Bubble");
return;
}
// 保留信息
_nextStep = nextStep;
_curBubble = bubble;
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
HideDialog();
// 如果仅由一个选项
if (dialogueOptions.Length == 1)
{
_options[0].ShowOption(dialogueOptions[0]);
}
else
{
for (var i = 0; i < dialogueOptions.Length; i++)
{
_options[i + 1].ShowOption(dialogueOptions[i]);
}
}
}
public void HideDialog()
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
textBubble.Hide();
}
HideOptions();
}
public bool TrySkipLine(bool isForceSkip = false)
{
if (!_curBubble)
{
return true;
}
if (_curBubble && _curBubble.IsShowingText)
{
_curBubble.SkipLine();
return true;
}
return false;
}
public void NextStep()
{
if (_nextStep == null) return;
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
_curBubble?.Hide();
_curBubble = null;
next?.Invoke();
}
public void OnLocalizationChanged(string value)
{
}
#endregion
private void HideDialog(Bubble activeBubble)
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
if (activeBubble != textBubble)
{
textBubble.Hide();
}
}
HideOptions();
}
private bool TryGetBubble(ActorRole role, int idx, out Bubble bubble)
{
if (_bubbleDict.TryGetValue(role, out var bubbles))
{
bubble = bubbles.FirstOrDefault(item => item.idx == idx);
return bubble != null;
}
bubble = null;
return false;
}
private void HideOptions()
{
foreach (var option in _options)
{
option.Hide();
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a76234ef7ee34400b306a4823081ba62
timeCreated: 1749022020
@@ -0,0 +1,44 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class BubbleOption : MonoBehaviour
{
public int optionIdx;
private TMP_Text _text;
private DialogOption _option;
private Button _button;
public void Awake()
{
_text = GetComponentInChildren<TMP_Text>();
_button = GetComponent<Button>();
}
public void LoadData(BubbleOptionSlotData data)
{
((RectTransform)transform).localPosition = UIManager.GetDialogUIPos(data.slotPosition);
}
public void ShowOption(DialogOption dialogOption)
{
gameObject.SetActive(true);
_button.onClick.RemoveAllListeners();
_text.text = "";
// 清理旧数据
gameObject.SetActive(true);
_text.text = dialogOption.Line;
_button.onClick.AddListener(() =>
{
dialogOption.Select();
});
}
public void Hide()
{
gameObject.SetActive(false);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 468ec4615ee64b2cb5ef8b1a66339dac
timeCreated: 1749024963
@@ -0,0 +1,27 @@
using System;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream
{
public class BubbleOptionSlot : MonoBehaviour
{
[SerializeField] private BubbleOptionSlotData data;
public BubbleOptionSlotData Data
{
get
{
data.slotPosition = CameraKit.GetScreenPos(transform.position);
return data;
}
}
}
[Serializable]
public struct BubbleOptionSlotData
{
[HideInInspector] public Vector3 slotPosition;
public int optionIdx;
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 98b5d94e03211a94bba6de692a1d405a
guid: c1a72c4bf33546244b7030c41b1b2b05
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -0,0 +1,83 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
namespace AibisDream
{
public class BubbleSlot : MonoBehaviour
{
[SerializeField] private BubbleSlotData data;
public BubbleSlotData Data
{
get
{
data.slotPosition = CameraKit.GetScreenPos(transform.position);
return data;
}
}
private void OnDrawGizmos()
{
// 画一个矩形
Gizmos.color = Color.white;
// 计算长和宽
var width = data.maxWidth / 108f;
var height = 0.5f * width;
// 根据PivotType确定矩形位置
var centerNormal = GetSquareCenterOffset(data.pivotType);
// Calculate the corners of the square
var topLeftNormal = centerNormal + new Vector3(-0.5f, 0.5f, 0);
var topRightNormal = centerNormal + new Vector3(0.5f, 0.5f, 0);
var bottomLeftNormal = centerNormal + new Vector3(-0.5f, -0.5f, 0);
var bottomRightNormal = centerNormal + new Vector3(0.5f, -0.5f, 0);
// 计算实际位置
var topLeft = new Vector3(topLeftNormal.x * width, topLeftNormal.y * height, 0) + transform.position;
var topRight = new Vector3(topRightNormal.x * width, topRightNormal.y * height, 0) + transform.position;
var bottomLeft = new Vector3(bottomLeftNormal.x * width, bottomLeftNormal.y * height, 0) + transform.position;
var bottomRight = new Vector3(bottomRightNormal.x * width, bottomRightNormal.y * height, 0) + transform.position;
// Draw the square
Gizmos.DrawLine(topLeft, topRight);
Gizmos.DrawLine(topRight, bottomRight);
Gizmos.DrawLine(bottomRight, bottomLeft);
Gizmos.DrawLine(bottomLeft, topLeft);
// pivot画圆
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, 0.05f);
}
private static Vector3 GetSquareCenterOffset(PivotType pivotType)
{
return pivotType switch
{
PivotType.Top => new Vector3(0, -0.5f, 0),
PivotType.Bottom => new Vector3(0, 0.5f, 0),
PivotType.Left => new Vector3(0.5f, 0, 0),
PivotType.Right => new Vector3(-0.5f, 0, 0),
PivotType.TopLeft => new Vector3(0.5f, -0.5f, 0),
PivotType.TopRight => new Vector3(-0.5f, -0.5f, 0),
PivotType.BottomLeft => new Vector3(0.5f, 0.5f, 0),
PivotType.BottomRight => new Vector3(-0.5f, 0.5f, 0),
PivotType.Center => Vector3.zero,
_ => Vector3.zero
};
}
}
[Serializable]
public struct BubbleSlotData
{
[HideInInspector] public Vector3 slotPosition;
public ActorRole actorRole;
public int idx;
public int maxWidth;
public int minWidth;
public BubbleStyle bubbleStyle;
public PivotType pivotType;
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8a4b8d325dce1b64980f8fd2ff77c571
guid: bbc0dde0e8b8a9c498545e1b5b508241
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -0,0 +1,46 @@
using System;
using System.Linq;
using UnityEngine;
namespace AibisDream
{
public class BubbleSlotGroup : MonoBehaviour
{
[SerializeField] private BubbleSlotGroupData data;
public BubbleSlotGroupData CollectData()
{
// 获取子类
var bubbleSlots = GetComponentsInChildren<BubbleSlot>();
var optionSlots = GetComponentsInChildren<BubbleOptionSlot>();
// 抽取数据
data.bubbleSlots = bubbleSlots.Select(item => item.Data).ToArray();
if (optionSlots is { Length: 0 })
{
data.bubbleOptionSlots = optionSlots.Select(item => item.Data).ToArray();
}
return data;
}
}
[Serializable]
public struct BubbleSlotGroupData
{
public DialogViewType dialogViewType;
[HideInInspector] public BubbleSlotData[] bubbleSlots;
[HideInInspector] public BubbleOptionSlotData[] bubbleOptionSlots;
}
public enum PivotType {
Top,
Bottom,
Left,
Right,
TopLeft,
TopRight,
BottomLeft,
BottomRight,
Center
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8225446392f64688813d628ffb56cc7c
timeCreated: 1749042853
+17 -3
View File
@@ -1,6 +1,7 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
@@ -14,6 +15,8 @@ namespace AibisDream
public GameObject choiceButtonPrefab;
#endregion
private TextParam _textParam;
private void Awake()
{
@@ -21,7 +24,7 @@ namespace AibisDream
_ => HideDialog());
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
Debug.Log("CenterOption只显示选项");
}
@@ -42,8 +45,14 @@ namespace AibisDream
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, transform);
choiceInstance.GetComponentInChildren<TMP_Text>().text = option.Line;
choiceInstance.GetComponent<Button>().onClick.AddListener(option.Select);
var optionText = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
optionText.text = option.Line;
optionText.characterSpacing = _textParam.charSpace;
choiceInstance.GetComponent<Button>().onClick.AddListener(() =>
{
HideDialog();
option.Select();
});
}
}
@@ -62,5 +71,10 @@ namespace AibisDream
{
// 无法继续
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
}
}
}
+14 -29
View File
@@ -3,6 +3,7 @@ using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
@@ -17,16 +18,12 @@ namespace AibisDream
private Action _nextStep;
#endregion
private bool _skipLineDelay;
[Header("跳过阻塞延迟时间/ms")] [SerializeField]
private int delayTime = 300;
private TextParam _textParam;
private void Awake()
{
InitComponents();
AddSomeListener();
}
private void InitComponents()
@@ -34,17 +31,7 @@ namespace AibisDream
_dialogText = transform.Find("Dialog Text")?.gameObject.GetComponent<TypewriterByCharacter>();
}
private void AddSomeListener()
{
// 对话显示后有一段延时不可跳过
_dialogText.onTypewriterStart.AddListener(() =>
{
_skipLineDelay = true;
_ = CommonUtil.Delay(delayTime, () => { _skipLineDelay = false; });
});
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
// 把原有对话清掉
ClearBox();
@@ -58,12 +45,6 @@ namespace AibisDream
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
// 执行自动跳过结局
if (isAutoSkip)
{
_dialogText.onTextShowed.AddListener(() => _ = CommonUtil.Delay(200, NextStep));
}
}
public void ShowOptions(DialogOption[] dialogueOptions)
@@ -78,11 +59,6 @@ namespace AibisDream
public bool TrySkipLine(bool isForceSkip)
{
if (_skipLineDelay && !isForceSkip)
{
return true;
}
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
@@ -102,7 +78,16 @@ namespace AibisDream
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
}
private void ClearBox()
{
gameObject.SetActive(true);
+204 -8
View File
@@ -1,16 +1,212 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class DialogBox : DialogBoxBase
public class DialogBox : MonoBehaviour, IDialogView
{
[SerializeField] protected GameObject choiceButton;
protected override void OnAwake()
#region box组件名称
private const string ActorName = "Actor Name";
private const string DialogText = "Dialog Text";
private const string NextArray = "Next Array";
private const string ChoiceBox = "Choice Box";
#endregion
#region box组件
private TypewriterByCharacter _dialogText;
private TextMeshProUGUI _actorName;
private GameObject _nextArray;
private GameObject _choiceBox;
#endregion
private TextParam _textParam;
private Action _nextStep;
[SerializeReference] private GameObject choiceButtonPrefab;
private void Awake()
{
// 初始化选择按钮
choiceButtonPrefab = choiceButton;
InitComponents();
RegisterEvents();
}
#region
private void InitComponents()
{
_actorName = transform.Find(ActorName)?.gameObject.GetComponentInChildren<TextMeshProUGUI>();
_dialogText = transform.Find(DialogText)?.gameObject.GetComponent<TypewriterByCharacter>();
_nextArray = transform.Find(NextArray)?.gameObject;
_choiceBox = transform.Find(ChoiceBox)?.gameObject;
}
private void RegisterEvents()
{
_dialogText.onTextShowed.AddListener(OnTextShowed);
}
#endregion
/// <summary>
/// 隐藏对话盒
/// </summary>
public void HideDialog()
{
gameObject.SetActive(false);
}
/// <summary>
/// 显示对话
/// </summary>
/// <param name="dialogLine">对话内容</param>
/// <param name="character">角色内容</param>
/// <param name="nextStep">下一步</param>
/// <param name="lineId">行号</param>
/// <param name="isAutoSkip">是否自动跳过,默认为false</param>
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
gameObject.SetActive(true);
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
_choiceBox?.SetActive(false);
// 显示内容
ShowActorName(character);
_dialogText.ShowText(dialogLine);
_nextStep = nextStep;
}
private void OnTextShowed()
{
_nextArray.gameObject.SetActive(true);
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
}
public void NextStep()
{
if (_nextStep == null) return;
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
// 关闭对话
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
_actorName.characterSpacing = _textParam.charSpace;
}
/// <summary>
/// 展示选项
/// </summary>
/// <param name="dialogueOptions">对话选项</param>
public void ShowOptions(DialogOption[] dialogueOptions)
{
gameObject.SetActive(true);
// 没有选择框直接不显示选项
if (!_choiceBox)
{
return;
}
// 把原有对话清掉
ClearBox();
_choiceBox.SetActive(true);
_dialogText.gameObject.SetActive(false);
HideActorName();
// 销毁原来的按钮
foreach (Transform child in _choiceBox.transform)
{
Destroy(child.gameObject);
}
// 生成新按钮
foreach (var option in dialogueOptions)
{
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, _choiceBox.transform);
var optionText = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();
optionText.text = option.Line;
optionText.characterSpacing = _textParam.charSpace;
choiceInstance.GetComponent<Button>().onClick.AddListener(() =>
{
HideDialog();
option.Select();
});
}
}
/// <summary>
/// 尝试跳过对话
/// true说明成功快进了对话显示
/// false说明对话已经显示完成了,可以跳过
/// </summary>
/// <returns></returns>
public bool TrySkipLine(bool isForceSkip)
{
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
_nextArray.gameObject.SetActive(false);
return false;
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.ShowText("");
_nextArray?.SetActive(false);
if (!_actorName) _actorName.text = "";
}
private void ShowActorName(CharacterVo character)
{
if (!_actorName) return;
if (string.IsNullOrWhiteSpace(character.key))
{
_actorName.transform.parent.gameObject.SetActive(false);
}
else
{
_actorName.transform.parent.localPosition =
character.key == "me" ? new Vector3(310, 95, 0) : new Vector3(-458, 95, 0);
_actorName.transform.parent.gameObject.SetActive(true);
_actorName.text = character.GetActorName();
}
}
private void HideActorName()
{
_actorName.transform.parent.gameObject.SetActive(false);
}
}
}
}
-213
View File
@@ -1,213 +0,0 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public abstract class DialogBoxBase : MonoBehaviour, IDialogView
{
#region box组件名称
private const string ActorName = "Actor Name";
private const string DialogText = "Dialog Text";
private const string NextArray = "Next Array";
private const string ChoiceBox = "Choice Box";
#endregion
#region box组件
private TypewriterByCharacter _dialogText;
private TextMeshProUGUI _actorName;
private GameObject _nextArray;
private GameObject _choiceBox;
#endregion
private bool _skipLineDelay;
private Action _nextStep;
[Header("跳过阻塞延迟时间/ms")] [SerializeField]
private int delayTime = 300;
protected GameObject choiceButtonPrefab;
private void Awake()
{
InitComponents();
AddSomeListener();
}
private void AddSomeListener()
{
// 对话显示后有一段延时不可跳过
_dialogText.onTypewriterStart.AddListener(() =>
{
_skipLineDelay = true;
_ = CommonUtil.Delay(delayTime, () => { _skipLineDelay = false; });
});
}
#region
private void InitComponents()
{
_actorName = transform.Find(ActorName)?.gameObject.GetComponentInChildren<TextMeshProUGUI>();
_dialogText = transform.Find(DialogText)?.gameObject.GetComponent<TypewriterByCharacter>();
_nextArray = transform.Find(NextArray)?.gameObject;
_choiceBox = transform.Find(ChoiceBox)?.gameObject;
OnAwake();
}
protected virtual void OnAwake()
{
}
#endregion
/// <summary>
/// 隐藏对话盒
/// </summary>
public void HideDialog()
{
gameObject.SetActive(false);
}
/// <summary>
/// 显示对话
/// </summary>
/// <param name="dialogLine">对话内容</param>
/// <param name="character">角色内容</param>
/// <param name="nextStep">下一步</param>
/// <param name="onTextShowed">文字展示结束后触发</param>
/// <param name="isAutoSkip">是否自动跳过,默认为false</param>
public virtual void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
{
gameObject.SetActive(true);
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
_choiceBox?.SetActive(false);
// 显示内容
ShowActorName(character);
_dialogText.ShowText(dialogLine);
// 自动跳过的回调很难独立Remove,只能全部清空再注册,下策
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => _nextArray.gameObject.SetActive(true));
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
// 执行自动跳过结局
if (isAutoSkip)
{
_dialogText.onTextShowed.AddListener(() => _ = CommonUtil.Delay(200, NextStep));
}
}
public virtual void NextStep()
{
if (_nextStep == null) return;
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
/// <summary>
/// 展示选项
/// </summary>
/// <param name="dialogueOptions">对话选项</param>
public virtual void ShowOptions(DialogOption[] dialogueOptions)
{
gameObject.SetActive(true);
// 没有选择框直接不显示选项
if (!_choiceBox)
{
return;
}
// 把原有对话清掉
ClearBox();
_choiceBox.SetActive(true);
_dialogText.gameObject.SetActive(false);
// 销毁原来的按钮
foreach (Transform child in _choiceBox.transform)
{
Destroy(child.gameObject);
}
// 生成新按钮
foreach (var option in dialogueOptions)
{
if (!option.IsAvailable) continue;
var choiceInstance = Instantiate(choiceButtonPrefab, _choiceBox.transform);
choiceInstance.GetComponentInChildren<TextMeshProUGUI>().text = option.Line;
choiceInstance.GetComponent<Button>().onClick.AddListener(option.Select);
}
}
/// <summary>
/// 尝试跳过对话
/// true说明成功快进了对话显示
/// false说明对话已经显示完成了,可以跳过
/// </summary>
/// <returns></returns>
public virtual bool TrySkipLine(bool isForceSkip)
{
if (_skipLineDelay && !isForceSkip)
{
return true;
}
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
else
{
_nextArray.gameObject.SetActive(false);
return false;
}
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.ShowText("");
_nextArray?.SetActive(false);
if (!_actorName) _actorName.text = "";
}
private void ShowActorName(CharacterVo character)
{
if (!_actorName) return;
if (string.IsNullOrWhiteSpace(character.GetActorName()))
{
_actorName.transform.parent.gameObject.SetActive(false);
}
else
{
_actorName.transform.parent.localPosition =
character.key == "me" ? new Vector3(310, 95, 0) : new Vector3(-458, 95, 0);
_actorName.transform.parent.gameObject.SetActive(true);
_actorName.text = character.GetActorName();
}
}
}
}
@@ -1,12 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AibisDream
{
public class DialogBubble : DialogBoxBase
{
// 气泡功能比较简单似乎不需要加别的
}
}
@@ -1,113 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Kit;
using UnityEngine;
namespace AibisDream
{
public class DialogBubbleViewer : MonoBehaviour, IDialogView
{
private const string PlayerBubble = "Player Bubble";
private const string ActorBubble = "Actor Bubble";
private const string NormalBox = "Normal Box";
private IDialogView _normalBox;
private IDialogView _playerBubble;
private IDialogView _actorBubble;
private List<IDialogView> _dialogViews;
private IDialogView _currentView;
private Action _nextStep;
private void Awake()
{
Init();
}
private void Init()
{
_normalBox = transform.Find(NormalBox).GetComponent<IDialogView>();
_playerBubble = transform.Find(PlayerBubble).GetComponent<IDialogView>();
_actorBubble = transform.Find(ActorBubble).GetComponent<IDialogView>();
_dialogViews = new List<IDialogView> { _normalBox, _playerBubble, _actorBubble };
_dialogViews.ForEach(item => item.HideDialog());
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
{
gameObject.SetActive(true);
// 根据角色信息气泡
_currentView = SelectBubbleByCharacter(character);
// 处理其他泡泡
ProcessOtherBox();
// 显示对话
_currentView.ShowLine(dialogLine, character, nextStep, isAutoSkip);
}
public void ShowOptions(DialogOption[] options)
{
gameObject.SetActive(true);
_currentView = _normalBox;
// 目前只有正常Box可以展示选项
// 处理其他泡泡
ProcessOtherBox();
// 展示选项
_normalBox.ShowOptions(options);
}
public void HideDialog()
{
gameObject.SetActive(false);
// 隐藏整个对话组件
_dialogViews?.ForEach(item => item.HideDialog());
}
public bool TrySkipLine(bool isForceSkip = false)
{
return _currentView == null || _currentView.TrySkipLine(isForceSkip);
}
public void NextStep()
{
_currentView.NextStep();
}
private IDialogView SelectBubbleByCharacter(CharacterVo characterVo)
{
var targetBubble = characterVo.role switch
{
ActorRole.Player => _playerBubble,
ActorRole.MainActor => _actorBubble,
ActorRole.Aside => _normalBox,
_ => _normalBox
};
foreach (var bubble in _dialogViews.Where(bubble => bubble != targetBubble))
{
bubble.HideDialog();
}
return targetBubble;
}
private void ProcessOtherBox()
{
if (_currentView == _actorBubble || _currentView == _playerBubble)
{
_normalBox.HideDialog();
}
if (_currentView == _normalBox)
{
_actorBubble.HideDialog();
_playerBubble.HideDialog();
}
}
}
}
+160 -68
View File
@@ -1,23 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using AibisDream.Framework;
using AibisDream.Kit;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class DialogCanvasManager : Singleton<DialogCanvasManager>, IDialogView
{
private const string QuickTalk = "Quick Talk";
#region
private readonly Dictionary<DialogViewType, IDialogView> _dialogViewDict = new();
private IDialogView _curView;
private IDialogView _lastShowView;
private GameObject _quickTalkButton;
private IDialogView _defaultView;
private IDialogView _showingView;
private IActionController _autoNext;
private IActionController _block;
private IActionController _hideDialog;
public TMP_Text widthEstimation;
#endregion
#region
[SerializeField] private float blockDuration;
[SerializeField] private float autoSkipDelay;
[SerializeField] private float autoHideDuration;
private bool _isNextAutoSkip;
private bool _isNextBlocked;
#endregion
@@ -25,25 +39,27 @@ namespace AibisDream
public override void OnSingletonInit()
{
InitQuickTalkButton();
InitEvent();
// 默认对话框直接加载
var box = transform.Find("Dialog Box").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.OldBox, box);
var centerText = transform.Find("Center Text").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterText, centerText);
var centerOption = transform.Find("Center Option").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterOption, centerOption);
}
private void Start()
{
_curView = _dialogViewDict[DialogViewType.OldBox];
// 默认对话框直接加载
// var box = transform.Find("Dialog Box").GetComponent<IDialogView>();
// RegisterDialogView(DialogViewType.OldBox, box);
var centerText = transform.Find("Center Text").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterText, centerText);
var centerOption = transform.Find("Center Option").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.CenterOption, centerOption);
var bubbleGroup = transform.Find("Bubble Group").GetComponent<IDialogView>();
RegisterDialogView(DialogViewType.StandardBubble, bubbleGroup);
_defaultView = _dialogViewDict[DialogViewType.StandardBubble];
}
private void InitEvent()
{
// 记录相关
_rmvList.Add(
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart,
AddDialogueLine));
@@ -51,6 +67,45 @@ namespace AibisDream
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.OptionSelected,
AddDialogueLine));
_rmvList.Add(EnumEventSystem.Global.Register(EventEnum.NextYarn, CleanDialogHistory));
// 文本显示事件
_rmvList.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnTextShown));
_rmvList.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineEnd, OnTextEnd));
}
private void OnTextShown()
{
// 阻塞部分
_isNextBlocked = true;
_block = ActionKit.Delay(blockDuration, () =>
{
_isNextBlocked = false;
_block = null;
}
).Start(this);
// 自动跳过部分
if (DialogController.Instance.quickRunMode) return;
if (DialogController.Instance.autoRunMode || _isNextAutoSkip)
{
_autoNext = ActionKit.Delay(autoSkipDelay, () =>
{
_autoNext = null;
NextStep();
}).Start(this);
_isNextAutoSkip = false;
}
}
private void OnTextEnd()
{
_block?.Deinit();
_block = null;
_isNextBlocked = false;
_autoNext?.Deinit();
_autoNext = null;
}
public override void OnSingletonDestroy()
@@ -73,29 +128,8 @@ namespace AibisDream
#endregion
private void Update()
{
if (Input.GetKeyDown(KeyCode.Q) && Input.GetKey(KeyCode.P))
{
_quickTalkButton.SetActive(!_quickTalkButton.activeSelf);
}
}
#region
private void InitQuickTalkButton()
{
_quickTalkButton = transform.Find(QuickTalk).gameObject;
_quickTalkButton.GetComponent<Button>().onClick.AddListener(SwitchQuickTalkMode);
}
private void SwitchQuickTalkMode()
{
DialogController.Instance.quickRunMode = !DialogController.Instance.quickRunMode;
_quickTalkButton.GetComponent<Image>().color =
DialogController.Instance.quickRunMode ? Color.gray : Color.white;
}
/// <summary>
/// 注册对话框
/// </summary>
@@ -119,30 +153,43 @@ namespace AibisDream
#region
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId,
bool isAutoSkip = false)
{
_isNextAutoSkip = isAutoSkip;
// 根据DialogViewType确定在哪个对话框显示
if (character.dialogViewType == DialogViewType.Default)
{
if (_lastShowView != _curView)
if (_showingView != _defaultView)
{
_lastShowView?.HideDialog();
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_lastShowView = _curView;
// 没有指定对话框,就用当前激活的
_curView.ShowLine(dialogLine, character, nextStep, isAutoSkip);
_showingView = _defaultView;
_showingView.ShowLine(dialogLine, character, nextStep, lineId, isAutoSkip);
}
else if (_dialogViewDict.TryGetValue(character.dialogViewType, out var view))
{
if (_lastShowView != view)
if (_showingView != view)
{
_lastShowView?.HideDialog();
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_lastShowView = view;
_showingView = view;
// 对于指定了对话框的,就在指定对话框显示
view.ShowLine(dialogLine, character, nextStep, isAutoSkip);
view.ShowLine(dialogLine, character, nextStep, lineId, isAutoSkip);
}
else
{
@@ -156,37 +203,72 @@ namespace AibisDream
// 根据状况选择不同的选择框
if (viewType == DialogViewType.Default)
{
_dialogViewDict[DialogViewType.OldBox].ShowOptions(dialogueOptions);
if (_showingView != _defaultView)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = _defaultView;
_showingView.ShowOptions(dialogueOptions);
}
else
else if(_dialogViewDict.TryGetValue(viewType, out var view))
{
_dialogViewDict[viewType].ShowOptions(dialogueOptions);
if (_showingView != view)
{
_showingView?.HideDialog();
}
else
{
_hideDialog?.Deinit();
_hideDialog = null;
}
_showingView = view;
_showingView.ShowOptions(dialogueOptions);
}
}
public void HideDialog()
{
_curView.HideDialog();
_showingView?.HideDialog();
}
public bool TrySkipLine(bool isForceSkip = false)
{
return _lastShowView != null && _lastShowView.TrySkipLine(isForceSkip);
if (_isNextBlocked)
{
return true;
}
return _showingView != null && _showingView.TrySkipLine(isForceSkip);
}
public void NextStep()
{
_lastShowView?.NextStep();
var view = _showingView;
_hideDialog = ActionKit.Delay(autoHideDuration, () =>
{
_hideDialog = null;
view.HideDialog();
}).Start(this);
_showingView?.NextStep();
}
public void OnLocalizationChanged(string value)
{
}
public void SwitchDialogView(DialogViewType dialogViewType)
{
if (_dialogViewDict.TryGetValue(dialogViewType, out var view))
{
_curView.HideDialog();
_lastShowView?.HideDialog();
_lastShowView = null;
_curView = view;
_defaultView?.HideDialog();
_showingView?.HideDialog();
_defaultView = view;
}
else
{
@@ -198,7 +280,7 @@ namespace AibisDream
#region
[Header("对话回顾组件")] [SerializeField] private TMP_Text logText;
private StringBuilder DialogRecord => UIManager.Instance.GetPanel<RecordPanel>().recordStr;
/// <summary>
/// 记录对话
@@ -206,25 +288,33 @@ namespace AibisDream
/// <param name="line">对话</param>
private void AddDialogueLine(DialogText line)
{
logText.text += line.GetDialogText();
DialogRecord.Append(line.GetDialogText());
}
private void CleanDialogHistory()
{
logText.text = null;
DialogRecord.Clear();
}
/// <summary>
/// 切换对话回顾展示状态
/// </summary>
public void ControlDialogHistory()
public void CloseCanvas()
{
var logObj = transform.Find("Dialogue Log").gameObject;
logObj.SetActive(!logObj.activeSelf);
EnumEventSystem.Global.Send(EventEnum.Menu, logObj.activeSelf);
gameObject.SetActive(false);
}
public void OpenCanvas()
{
gameObject.SetActive(true);
}
#endregion
public float EstimateTextWidth(string text, float fontSize)
{
widthEstimation.fontSize = fontSize;
widthEstimation.text = text;
widthEstimation.ForceMeshUpdate();
return widthEstimation.preferredWidth;
}
}
public enum DialogViewType
@@ -234,6 +324,8 @@ namespace AibisDream
OldBox,
Screen,
CenterText,
CenterOption
CenterOption,
Task,
StandardBubble
}
}
+11 -1
View File
@@ -10,7 +10,7 @@ namespace AibisDream
{
public interface IDialogView
{
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false);
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId ,bool isAutoSkip = false);
public void ShowOptions(DialogOption[] dialogueOptions);
@@ -19,6 +19,8 @@ namespace AibisDream
public bool TrySkipLine(bool isForceSkip = false);
public void NextStep();
public void OnLocalizationChanged(string value);
}
public struct DialogOption
@@ -62,4 +64,12 @@ namespace AibisDream
.Select(item => new DialogOption { _option = item, _onOptionSelected = onOptionSelected }).ToArray();
}
}
[Serializable]
public struct TextParam
{
public float charSpace;
public float lineSpace;
public int maxCharNum;
}
}
@@ -0,0 +1,44 @@
using AibisDream.Utility;
using TMPro;
using UnityEngine;
using UnityEngine.Localization.Components;
namespace AibisDream
{
[RequireComponent(typeof(TMP_Text))]
[RequireComponent(typeof(LocalizeStringEvent))]
public class LocalizedText : MonoBehaviour
{
private TMP_Text _text;
private LocalizeStringEvent _localizeEvent;
public bool isLineText = true;
public string template = "{0}";
private void OnUpdateString(string text)
{
if (isLineText)
{
text = CommonUtil.RemoveName(text);
}
_text.text = string.Format(template, text);
}
public void SetLocalizedText(string table, string entry)
{
_text = GetComponent<TMP_Text>();
_localizeEvent = GetComponent<LocalizeStringEvent>();
_localizeEvent.OnUpdateString.AddListener(OnUpdateString);
_localizeEvent.SetTable(table);
_localizeEvent.SetEntry(entry);
}
public void SetVariables()
{
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c9c71a7e9c9455d955ff20b5db823a1
timeCreated: 1746702086
+117
View File
@@ -0,0 +1,117 @@
using System;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class TempTextBox : MonoBehaviour, IDialogView
{
#region
private TypewriterByCharacter _dialogText;
private Image _panel;
private Action _nextStep;
#endregion
private bool _skipLineDelay;
private TextParam _textParam;
[Header("跳过阻塞延迟时间/ms")] [SerializeField]
private int delayTime = 300;
private void Awake()
{
InitComponents();
AddSomeListener();
}
private void InitComponents()
{
_dialogText = transform.Find("Dialog Text")?.gameObject.GetComponent<TypewriterByCharacter>();
}
private void AddSomeListener()
{
// 对话显示后有一段延时不可跳过
_dialogText.onTypewriterStart.AddListener(() =>
{
_skipLineDelay = true;
_ = CommonUtil.Delay(delayTime, () => { _skipLineDelay = false; });
});
}
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
// 把原有对话清掉
ClearBox();
_dialogText.gameObject.SetActive(true);
// 显示内容
_dialogText.ShowText(dialogLine);
// 自动跳过的回调很难独立Remove,只能全部清空再注册,下策
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
}
public void ShowOptions(DialogOption[] dialogueOptions)
{
// 不能出选项
}
public void HideDialog()
{
gameObject.SetActive(false);
}
public bool TrySkipLine(bool isForceSkip)
{
if (_skipLineDelay && !isForceSkip)
{
return true;
}
if (_dialogText.isShowingText)
{
_dialogText.SkipTypewriter();
return true;
}
return false;
}
public void NextStep()
{
if (_nextStep == null) return;
ClearBox();
EnumEventSystem.Global.Send(DialogEventEnum.LineEnd);
var next = _nextStep;
_nextStep = null;
next.Invoke();
}
public void OnLocalizationChanged(string value)
{
_textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = _dialogText.GetComponent<TMP_Text>();
// 修改对话文本
tmp.characterSpacing = _textParam.charSpace;
}
private void ClearBox()
{
gameObject.SetActive(true);
_dialogText?.TextAnimator.SetText("");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3bee0b70ea2946b8a6c59a4bceb04342
timeCreated: 1747292399
+12
View File
@@ -2,7 +2,10 @@ using System;
using AibisDream.Kit;
using AibisDream.Utility;
using Febucci.UI.Core;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using Object = System.Object;
namespace AibisDream.Framework
{
@@ -48,5 +51,14 @@ namespace AibisDream.Framework
{
gameObject.SetActive(false);
}
public void OnLocalizationChanged(string value)
{
var textParam = JsonUtil.ReadBeanByText<TextParam>(value);
var tmp = GetComponentInChildren<TMP_Text>();
tmp.characterSpacing = textParam.charSpace;
maxCharNum = textParam.maxCharNum;
}
}
}
+11 -25
View File
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using Unity.VisualScripting;
using UnityEngine;
namespace AibisDream
@@ -14,15 +14,10 @@ namespace AibisDream
#region
private bool _skipLineDelay;
private Action _nextStep;
private bool _isAutoSkip;
private TextBubble _curBubble;
[Header("跳过阻塞延迟时间/ms")] [SerializeField]
private int delayTime = 300;
#endregion
#region
@@ -54,16 +49,13 @@ namespace AibisDream
#endregion
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, bool isAutoSkip = false)
public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false)
{
gameObject.SetActive(true);
if (TryGetBubble(character.role, character.bubbleIdx ,out var bubble))
{
bubble.ShowLine(dialogLine, OnTextShowed);
// 设置延时
_skipLineDelay = true;
_ = CommonUtil.Delay(delayTime, () => { _skipLineDelay = false; });
// 将非选定的Bubble隐藏
HideDialog(bubble);
}
@@ -75,7 +67,6 @@ namespace AibisDream
// 保留信息
_nextStep = nextStep;
_isAutoSkip = isAutoSkip;
_curBubble = bubble;
}
@@ -88,7 +79,10 @@ namespace AibisDream
{
foreach (var textBubble in _bubbleDict.Values.SelectMany(inner => inner))
{
textBubble.Hide();
if (!textBubble.IsDestroyed())
{
textBubble.Hide();
}
}
}
@@ -98,18 +92,13 @@ namespace AibisDream
{
if (activeBubble != textBubble)
{
textBubble.Hide();
textBubble?.Hide();
}
}
}
public bool TrySkipLine(bool isForceSkip)
{
if (_skipLineDelay && !isForceSkip)
{
return true;
}
if (_curBubble.IsShowingText)
{
_curBubble.SkipLine();
@@ -132,17 +121,14 @@ namespace AibisDream
next?.Invoke();
}
public void OnLocalizationChanged(string value)
{
}
private void OnTextShowed()
{
// 触发事件
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
// 执行自动跳过结局
if (_isAutoSkip)
{
_ = CommonUtil.Delay(200, NextStep);
_isAutoSkip = false;
}
}
private bool TryGetBubble(ActorRole role, int idx, out TextBubble textBubble)
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5010337b422cfa74ea2d2939e762693e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+65
View File
@@ -0,0 +1,65 @@
using System;
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization.Components;
namespace AibisDream
{
/// <summary>
/// 表单项父类
/// </summary>
public abstract class AbsFormItem : MonoBehaviour
{
#region
public string prop;
public string label;
public abstract FieldType FieldType { get; }
#endregion
#region
private LocalizeStringEvent _labelRef;
public UnityEvent<string, string> OnValueChanged;
#endregion
private void Awake()
{
InitItem();
}
/// <summary>
/// 初始化FormItem
/// </summary>
private void InitItem()
{
// label设置
_labelRef = transform.Find("Label").GetComponent<LocalizeStringEvent>();
_labelRef.SetTable(ConstRef.UITextTable);
_labelRef.SetEntry(label);
// field设置
InitField();
}
protected abstract void InitField();
public abstract void SetValue(string value);
}
public enum FieldType
{
Input,
Slider,
Select,
Dropdown
}
[Serializable]
public struct UIFormOption
{
public string prop;
public string label;
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 429e0ca7a1096a1478e50195b88539b8
guid: dd06484c1f627d249ad5a16558c9cdb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
+32
View File
@@ -0,0 +1,32 @@
using TMPro;
namespace AibisDream
{
public class DropdownItem : AbsFormItem
{
public override FieldType FieldType => FieldType.Dropdown;
private TMP_Dropdown _dropdown;
protected override void InitField()
{
// 获取索引
_dropdown = GetComponentInChildren<TMP_Dropdown>(true);
// 注册事件
_dropdown.onValueChanged.AddListener(OnSelectChanged);
}
public override void SetValue(string value)
{
var target = _dropdown.options.FindIndex(item => item.text == value);
_dropdown.value = target;
}
private void OnSelectChanged(int value)
{
// 序号转字符串
var strValue = _dropdown.options[value].text;
OnValueChanged?.Invoke(prop, strValue);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39f0dc8bcf2641458cf3f8726add30f9
timeCreated: 1744702543
+15
View File
@@ -0,0 +1,15 @@
namespace AibisDream
{
/// <summary>
/// 表单接口。
/// 表单Root主要承担数据逻辑功能
/// 1. 修改表单数据时对应改动
/// 2. 从配置文件读取表单数据对应改动
/// 3. 表单初始化
/// </summary>
public interface IUIForm
{
public void OnItemChanged(string propName, string value);
public void UpdateForm();
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e80043371ab4923944ceda3823424b9
timeCreated: 1744619745
+68
View File
@@ -0,0 +1,68 @@
using System;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class LanguageItem : AbsFormItem
{
public override FieldType FieldType => FieldType.Select;
#region
private TMP_Text _showText;
private Button _leftBtn;
private Button _rightBtn;
#endregion
#region
[Header("可选项")]
public UIFormOption[] options;
private int _curIdx;
#endregion
protected override void InitField()
{
var field = transform.Find("Field");
_showText = field.Find("ShowText").GetComponent<TMP_Text>();
_leftBtn = field.Find("Left Btn").GetComponent<Button>();
_rightBtn = field.Find("Right Btn").GetComponent<Button>();
_leftBtn.onClick.AddListener(LeftRoll);
_rightBtn.onClick.AddListener(RightRoll);
}
public override void SetValue(string value)
{
var idx = Array.FindIndex(options, item => item.prop == value);
if (idx < 0)
{
Debug.LogError($"{prop} setting value error");
}
_curIdx = idx;
_showText.text = options[idx].label;
}
private void LeftRoll()
{
_curIdx = CommonUtil.LoopStep(_curIdx, 0, options.Length - 1);
_showText.text = options[_curIdx].label;
OnValueChanged?.Invoke(prop, options[_curIdx].prop);
}
private void RightRoll()
{
_curIdx = CommonUtil.LoopStep(_curIdx, 0, options.Length - 1, -1);
_showText.text = options[_curIdx].label;
OnValueChanged?.Invoke(prop, options[_curIdx].prop);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ae7f07f0b7da4a119b731f409ebbfeda
timeCreated: 1745478466
+70
View File
@@ -0,0 +1,70 @@
using System;
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.Localization.Components;
using UnityEngine.UI;
namespace AibisDream
{
public class SelectItem : AbsFormItem
{
public override FieldType FieldType => FieldType.Select;
#region
private LocalizeStringEvent _showText;
private Button _leftBtn;
private Button _rightBtn;
#endregion
#region
[Header("可选项")]
public UIFormOption[] options;
private int _curIdx;
#endregion
protected override void InitField()
{
var field = transform.Find("Field");
_showText = field.Find("ShowText").GetComponent<LocalizeStringEvent>();
_leftBtn = field.Find("Left Btn").GetComponent<Button>();
_rightBtn = field.Find("Right Btn").GetComponent<Button>();
_leftBtn.onClick.AddListener(LeftRoll);
_rightBtn.onClick.AddListener(RightRoll);
}
public override void SetValue(string value)
{
var idx = Array.FindIndex(options, item => item.prop == value);
if (idx < 0)
{
Debug.LogError($"{prop} setting value error");
}
_curIdx = idx;
_showText.SetEntry(options[idx].label);
}
private void LeftRoll()
{
_curIdx = CommonUtil.LoopStep(_curIdx, 0, options.Length - 1);
_showText.SetEntry(options[_curIdx].label);
OnValueChanged?.Invoke(prop, options[_curIdx].prop);
}
private void RightRoll()
{
_curIdx = CommonUtil.LoopStep(_curIdx, 0, options.Length - 1, -1);
_showText.SetEntry(options[_curIdx].label);
OnValueChanged?.Invoke(prop, options[_curIdx].prop);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef1de16c90b849ef86a4360768fc55f6
timeCreated: 1745473121
+51
View File
@@ -0,0 +1,51 @@
using UnityEngine;
namespace AibisDream
{
public class SettingForm : MonoBehaviour, IUIForm
{
#region
private AbsFormItem[] _formItems;
#endregion
public void Init()
{
// 获取索引
_formItems = GetComponentsInChildren<AbsFormItem>();
UpdateForm();
// 绑定变化
foreach (var formItem in _formItems)
{
formItem.OnValueChanged.AddListener(OnItemChanged);
}
}
public void UnInit()
{
// 绑定变化
foreach (var formItem in _formItems)
{
formItem.OnValueChanged.RemoveAllListeners();
}
}
public void OnItemChanged(string propName, string value)
{
SettingLoader.Instance.Write(propName, value);
}
public void UpdateForm()
{
var settingDict = SettingLoader.Instance.ReadAll();
foreach (var formItem in _formItems)
{
if (settingDict.TryGetValue(formItem.prop, out var value))
{
formItem.SetValue(value);
}
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6564f6671e32475c981a8c3c1ca63ffd
timeCreated: 1744622926
+42
View File
@@ -0,0 +1,42 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class SliderItem : AbsFormItem
{
public override FieldType FieldType => FieldType.Slider;
#region
private Slider _slider;
private TMP_Text _sliderText;
#endregion
protected override void InitField()
{
// 初始化索引
_slider = GetComponentInChildren<Slider>();
_sliderText = _slider.GetComponentInChildren<TMP_Text>(true);
// 绑定事件
_slider.onValueChanged.AddListener(OnSliderChanged);
}
private void OnSliderChanged(float value)
{
// 更新数字显示
_sliderText.text = Mathf.RoundToInt(value * 100).ToString();
// 触发修改事件
OnValueChanged.Invoke(prop, value.ToString("F2"));
}
public override void SetValue(string value)
{
var floatValue = float.Parse(value);
_slider.value = floatValue;
_sliderText.text = Mathf.RoundToInt(floatValue * 100).ToString();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6cb985d5e95047f88ddec878de7972a2
timeCreated: 1744617521
-200
View File
@@ -1,200 +0,0 @@
using System.Collections;
using AibisDream.Framework;
using AibisDream.Kit;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class MainUIController : Singleton<MainUIController>
{
private const string TVScene = "TV Scene";
private const string BlackImage = "Fade Image";
private const string NewsImage = "News";
private const string ObjPanel = "Show Obj";
#region ShowObj参数
[Header("Obj尺寸参数")] public float objWidth;
public float objHeight;
#endregion
#region
[SerializeField] private GameObject mainUIPanel;
private FadeImage _tvScene;
private FadeImage _blackImage;
private FadeImage _news;
private GameObject _objPanel;
private Image _objImage;
private Image _fullScreen;
#endregion
public override void OnSingletonInit()
{
InitChildObj();
}
public void Start()
{
EnumEventSystem.Global.Register(EventEnum.SceneUnload, OnSceneUnload);
}
private void OnSceneUnload()
{
StartCoroutine(HideFullScreen());
StartCoroutine(HideObj());
FadeOut(0.1f);
}
#region
public void FadeIn(float duration)
{
_blackImage.FadeIn(duration);
}
public IEnumerator FadeInSync(float duration)
{
return _blackImage.FadeInSync(duration);
}
public void FadeOut(float duration)
{
_blackImage.FadeOut(duration);
}
public IEnumerator FadeOutSync(float duration)
{
return _blackImage.FadeOutSync(duration);
}
#endregion
#region TV场景淡入淡出
public void TVFadeIn(float duration)
{
_tvScene.FadeIn(duration);
_news.FadeIn(duration);
}
public IEnumerator TVFadeInSync(float duration)
{
_news.FadeIn(duration);
return _tvScene.FadeInSync(duration);
}
public void TVFadeOut(float duration)
{
_tvScene.FadeOut(duration);
_news.FadeOut(duration);
}
public IEnumerator TVFadeOutSync(float duration)
{
_news.FadeOut(duration);
return _tvScene.FadeOutSync(duration);
}
public void SwitchTV(string newsName)
{
_news.SwitchImage($"Art/Background/{newsName}");
}
#endregion
/// <summary>
/// 隐藏整个UI
/// </summary>
public void HideMainUI()
{
mainUIPanel.SetActive(false);
}
public void ShowMainUI()
{
mainUIPanel.SetActive(true);
}
/// <summary>
/// 显示物体
/// </summary>
/// <returns>协程</returns>
public IEnumerator ShowObj(string picName)
{
_objPanel.gameObject.SetActive(true);
// 切换图片
var newSprite = Resources.Load<Sprite>($"Art/Obj/{picName}");
// 获取图片的长宽比
var imageAspect = (float)newSprite.texture.width / newSprite.texture.height;
// 计算新的尺寸
if (imageAspect > 1) // 宽图
{
var newHeight = objWidth / imageAspect;
_objImage.rectTransform.sizeDelta = new Vector2(objWidth, newHeight);
}
else // 高图
{
var newWidth = objHeight * imageAspect;
_objImage.rectTransform.sizeDelta = new Vector2(newWidth, objHeight);
}
// 淡入
_objImage.sprite = newSprite;
_objImage.gameObject.SetActive(true);
yield return _objImage.DOBlendableColor(Color.white, 1).WaitForCompletion();
}
public IEnumerator ShowFullScreen(string picName)
{
_fullScreen.sprite = Resources.Load<Sprite>($"Art/Obj/{picName}");
// 淡入
_fullScreen.gameObject.SetActive(true);
yield return _objImage.DOBlendableColor(Color.white, 1).WaitForCompletion();
}
public IEnumerator HideFullScreen()
{
_fullScreen.gameObject.SetActive(true);
yield return _objImage.DOBlendableColor(Color.clear, 1).WaitForCompletion();
_fullScreen.gameObject.SetActive(false);
}
/// <summary>
/// 隐藏物体
/// </summary>
/// <returns>协程</returns>
public IEnumerator HideObj()
{
_objImage.gameObject.SetActive(true);
yield return _objImage.DOBlendableColor(Color.clear, 1).WaitForCompletion();
_objImage.gameObject.SetActive(false);
_objPanel.SetActive(false);
}
private void InitChildObj()
{
var rawTvScene = transform.GetChild(0).Find(TVScene).gameObject.GetComponent<Image>();
_tvScene = new FadeImage(rawTvScene);
var rawBlackImage = transform.GetChild(0).Find(BlackImage).gameObject.GetComponent<Image>();
_blackImage = new FadeImage(rawBlackImage);
var rawNews = transform.GetChild(0).Find(NewsImage).gameObject.GetComponent<Image>();
_news = new FadeImage(rawNews);
_objPanel = transform.GetChild(0).Find(ObjPanel).gameObject;
_objImage = _objPanel.transform.GetChild(0).GetComponent<Image>();
_fullScreen = transform.GetChild(0).Find("Full Screen Image").GetComponent<Image>();
}
}
}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b3c03e9f6ddaadd408fba26d40f93c26
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+24
View File
@@ -0,0 +1,24 @@
using UnityEngine;
namespace AibisDream
{
public class DialogPanel : MonoBehaviour, IUIPanel
{
#region UI面板功能
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
public void Show()
{
gameObject.SetActive(true);
}
public void Hide()
{
gameObject.SetActive(false);
}
#endregion
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d43fa24173f81ea4ea102be91896826e
guid: 2ecd4df87fde33d4a8944917a863a6af
MonoImporter:
externalObjects: {}
serializedVersion: 2
+66
View File
@@ -0,0 +1,66 @@
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class EndPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
#region
public void Show()
{
// GameManager.Instance.PauseGame();
gameObject.SetActive(true);
RegisterButton();
}
public void Hide()
{
gameObject.SetActive(false);
UnRegisterButton();
// GameManager.Instance.ContinueGame();
}
#endregion
private void RegisterButton()
{
var returnBtn = transform.Find("返回").GetComponent<Button>();
returnBtn.onClick.AddListener(BackToMain);
var backToMain = transform.Find("问卷").GetComponent<Button>();
backToMain.onClick.AddListener(OpenFeedbackLink);
var quit = transform.Find("Bug反馈").GetComponent<Button>();
quit.onClick.AddListener(OpenBugLink);
}
private void UnRegisterButton()
{
var returnBtn = transform.Find("返回").GetComponent<Button>();
returnBtn.onClick.RemoveAllListeners();
var backToMain = transform.Find("问卷").GetComponent<Button>();
backToMain.onClick.RemoveAllListeners();
var quit = transform.Find("Bug反馈").GetComponent<Button>();
quit.onClick.RemoveAllListeners();
}
private void BackToMain()
{
UIManager.Instance.HidePanel<EndPanel>();
GameManager.Instance.QuitGame();
}
private void OpenFeedbackLink()
{
Application.OpenURL(ConstRef.SurveyURL);
}
private void OpenBugLink()
{
Application.OpenURL(ConstRef.BugSurveyURL);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 102c329e03bc4e4882e2beb365e3ae1b
timeCreated: 1745221838
+79
View File
@@ -0,0 +1,79 @@
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class MainPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
#region
public void Show()
{
gameObject.SetActive(true);
}
public void Hide()
{
gameObject.SetActive(false);
}
#endregion
private void Awake()
{
RegisterButton();
}
private void Update()
{
if (Input.GetKey(KeyCode.Q) && Input.GetKeyDown(KeyCode.P))
{
var obj = transform.Find("Top Bar").Find("Quick Forward").gameObject;
var active = obj.activeSelf;
obj.SetActive(!active);
}
}
private void RegisterButton()
{
// 为按钮注册事件
var topBar = transform.Find("Top Bar");
topBar.Find("Setting").GetComponent<Button>().onClick.AddListener(OpenSettingPanel);
topBar.Find("Record").GetComponent<Button>().onClick.AddListener(OpenRecordPanel);
// 自动跳过和快进包括状态变换
var auto = topBar.Find("Auto Skip").GetComponent<BoolButton>();
auto.OnClick.AddListener(AutoSkip);
auto.getBool = () => DialogController.Instance.autoRunMode;
var ffwd = topBar.Find("Quick Forward").GetComponent<BoolButton>();
ffwd.OnClick.AddListener(QuickForward);
ffwd.getBool = () => DialogController.Instance.quickRunMode;
}
private void AutoSkip()
{
DialogController.Instance.autoRunMode = !DialogController.Instance.autoRunMode;
}
private void QuickForward()
{
DialogController.Instance.quickRunMode = !DialogController.Instance.quickRunMode;
Time.timeScale = DialogController.Instance.quickRunMode ? 8f : 1f;
}
private void OpenSettingPanel()
{
UIManager.Instance.ShowPanel<SettingPanel>();
}
private void OpenRecordPanel()
{
UIManager.Instance.ShowPanel<RecordPanel>();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4518044cbe67a4647af3110956c37758
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+199
View File
@@ -0,0 +1,199 @@
using System.Collections;
using AibisDream.Framework;
using AibisDream.Kit;
using DG.Tweening;
using RainbowArt.CleanFlatUI;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
/// <summary>
/// 主要用来放置淡入淡出,图片展示等演出工具
/// </summary>
public class PlayToolPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
[Header("Obj尺寸参数")] public float objWidth;
public float objHeight;
#region
private Image _fadeImage;
private GameObject _showObjPanel;
private Image _showObjImage;
private Image _fullScreenImage;
private Image _redFlash;
private ModalWindowProgressBar _window;
private ModalWindow _warningWindow;
#endregion
private void Awake()
{
InitRefs();
EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, HideAll);
}
private void InitRefs()
{
_fadeImage = transform.Find("Fade Image").GetComponent<Image>();
_showObjPanel = transform.Find("Show Obj").gameObject;
_showObjImage = _showObjPanel.transform.Find("Obj").GetComponent<Image>();
_fullScreenImage = transform.Find("Full Screen Image").GetComponent<Image>();
_window = transform.Find("进度条窗口").GetComponent<ModalWindowProgressBar>();
_redFlash = transform.Find("Red Flash").GetComponent<Image>();
_warningWindow = transform.Find("警告窗口").GetComponent<ModalWindow>();
}
public IEnumerator FadeInAsync(float duration = 1)
{
return _fadeImage.FadeInAsync(duration);
}
public IEnumerator FadeOutAsync(float duration = 1)
{
return _fadeImage.FadeOutAsync(duration);
}
public void FadeInSync(float duration = 1)
{
StartCoroutine(FadeInAsync(duration));
}
public void FadeOutSync(float duration = 1)
{
StartCoroutine(FadeOutAsync(duration));
}
/// <summary>
/// 显示物体
/// </summary>
/// <returns>协程</returns>
public IEnumerator ShowObj(string picName)
{
_showObjPanel.gameObject.SetActive(true);
// 切换图片
var newSprite = Resources.Load<Sprite>($"Art/Obj/{picName}");
// 获取图片的长宽比
var imageAspect = (float)newSprite.texture.width / newSprite.texture.height;
// 计算新的尺寸
if (imageAspect > 1) // 宽图
{
var newHeight = objWidth / imageAspect;
_showObjImage.rectTransform.sizeDelta = new Vector2(objWidth, newHeight);
}
else // 高图
{
var newWidth = objHeight * imageAspect;
_showObjImage.rectTransform.sizeDelta = new Vector2(newWidth, objHeight);
}
// 淡入
_showObjImage.sprite = newSprite;
yield return _showObjImage.FadeInAsync(1);
}
public IEnumerator HideObj()
{
yield return _showObjImage.FadeOutAsync(1);
_showObjPanel.SetActive(false);
}
public IEnumerator ShowFullScreen(string picName)
{
_fullScreenImage.sprite = Resources.Load<Sprite>($"Art/Obj/{picName}");
// 淡入
yield return _fullScreenImage.FadeInAsync(1);
}
public IEnumerator HideFullScreen()
{
return _fullScreenImage.FadeOutAsync(1);
}
public IEnumerator OpenProgressWindow(string title, string description, float duration)
{
AudioManager.Instance.PlaySfx("event:/Scriptal/Ui");
_window.TitleValue = title;
_window.DescriptionValue = description;
float currentProgress = 0;
DOTween.To(
() => currentProgress,
value =>
{
currentProgress = value;
_window.SetProgress(currentProgress); // 更新进度
},
100,
duration
);
_window.ShowModalWindow();
// 获取 moveText 的 RectTransform
RectTransform moveTextRect =
_window.transform.Find("View/mask/moveText")?.GetComponent<RectTransform>();
if (moveTextRect != null)
{
moveTextRect.DOAnchorPosY(0f, duration).SetEase(Ease.Linear);
}
// 等待用户确认
yield return new WaitUntil(() => currentProgress >= 100);
_window.HideModalWindow();
moveTextRect.DOAnchorPosY(1326f, 0.1f).SetEase(Ease.Linear);
}
// 红色闪烁效果
public IEnumerator FlashRed(float duration)
{
_redFlash.gameObject.SetActive(true);
yield return _redFlash.FadeInAsync(duration / 2);
yield return _redFlash.FadeOutAsync(duration / 2);
_redFlash.gameObject.SetActive(false);
}
private void HideAll()
{
_fullScreenImage.FadeOut(0.1f);
_showObjImage.FadeOut(0.1f);
_showObjPanel.SetActive(false);
}
#region
public void Show()
{
gameObject.SetActive(true);
}
public void Hide()
{
gameObject.SetActive(false);
}
#endregion
/// <summary>
/// 打开警告窗口
/// </summary>
/// <param name="description">警告描述文本</param>
/// <returns>等待玩家确认的协程</returns>
public IEnumerator OpenWarningWindow(string description)
{
AudioManager.Instance.PlaySfx("event:/Scriptal/Ui");
_warningWindow.DescriptionValue = description;
_warningWindow.ShowModalWindow();
// 等待玩家点击确认按钮
yield return new WaitUntil(() => !_warningWindow.gameObject.activeSelf);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ae9caaab66fd459493d673ef3fd524f2
timeCreated: 1744779595
+52
View File
@@ -0,0 +1,52 @@
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class RecordPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => true;
public readonly StringBuilder recordStr = new();
public void Show()
{
ShowText();
GameManager.Instance.PauseGame();
gameObject.SetActive(true);
var btn = transform.Find("Return").GetComponent<Button>();
btn.onClick.AddListener(ReturnGame);
}
public void Hide()
{
gameObject.SetActive(false);
GameManager.Instance.ContinueGame();
// 关闭时停止渲染
ClearText();
var btn = transform.Find("Return").GetComponent<Button>();
btn.onClick.RemoveAllListeners();
}
private void ShowText()
{
var text = transform.Find("Log View").GetComponentInChildren<TMP_Text>();
text.text = recordStr.ToString();
}
private void ClearText()
{
var text = transform.Find("Log View").GetComponentInChildren<TMP_Text>();
text.text = null;
}
private void ReturnGame()
{
UIManager.Instance.HidePanel<RecordPanel>();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dc6a1b2ccb564028b69d821ab33778f5
timeCreated: 1744779271
+77
View File
@@ -0,0 +1,77 @@
using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class SavesPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => true;
private static readonly string SaveFilePath = Application.streamingAssetsPath + "/SaveFiles";
#region
public Button buttonPrefab;
public Transform buttonParent;
#endregion
#region
public void Show()
{
InitLevelBtn();
gameObject.SetActive(true);
RegisterButton();
}
public void Hide()
{
gameObject.SetActive(false);
UnRegisterButton();
}
private void RegisterButton()
{
var returnBtn = transform.Find("Return").GetComponent<Button>();
returnBtn.onClick.AddListener(() => UIManager.Instance.HidePanel<SavesPanel>());
}
private void UnRegisterButton()
{
var returnBtn = transform.Find("Return").GetComponent<Button>();
returnBtn.onClick.RemoveAllListeners();
}
#endregion
private void InitLevelBtn()
{
// 清空旧按钮
foreach (Transform child in buttonParent)
{
Destroy(child.gameObject);
}
// 加载存档文件
string[] saveFiles = Directory.GetFiles(SaveFilePath, "*.json");
var orderedSaveFiles = saveFiles.OrderByDescending(item => item).ToArray();
foreach (var saveFile in orderedSaveFiles)
{
var button = Instantiate(buttonPrefab, buttonParent);
button.GetComponentInChildren<TMP_Text>().text = Path.GetFileNameWithoutExtension(saveFile);
button.onClick.AddListener(() => OnSaveFileSelected(saveFile));
}
}
private void OnSaveFileSelected(string saveFileName)
{
// 隐藏UI
gameObject.SetActive(false);
// 开始游戏
GameManager.Instance.StartWithSaveFile(saveFileName);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bdd86c19be1449ca9e2783eb714fb8ff
timeCreated: 1745572533
+81
View File
@@ -0,0 +1,81 @@
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class SettingPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => true;
#region
public void Show()
{
// 暂停游戏
GameManager.Instance.PauseGame();
gameObject.SetActive(true);
// 更新表单内容
var form = GetComponentInChildren<SettingForm>();
form.Init();
// 注册函数
RegisterButton();
}
public void Hide()
{
// 更新表单内容
var form = GetComponentInChildren<SettingForm>();
form.UnInit();
UnRegisterButton();
gameObject.SetActive(false);
// 继续游戏
GameManager.Instance.ContinueGame();
}
#endregion
private void RegisterButton()
{
var buttonGroup = transform.Find("Button Group");
var continueBtn = buttonGroup.Find("Continue").GetComponent<Button>();
continueBtn.onClick.AddListener(BackToGame);
var backToMain = buttonGroup.Find("BackMain").GetComponent<Button>();
backToMain.onClick.AddListener(BackToMain);
var quit = buttonGroup.Find("Quit").GetComponent<Button>();
quit.onClick.AddListener(Quit);
}
private void UnRegisterButton()
{
var buttonGroup = transform.Find("Button Group");
var continueBtn = buttonGroup.Find("Continue").GetComponent<Button>();
continueBtn.onClick.RemoveAllListeners();
var backToMain = buttonGroup.Find("BackMain").GetComponent<Button>();
backToMain.onClick.RemoveAllListeners();
var quit = buttonGroup.Find("Quit").GetComponent<Button>();
quit.onClick.RemoveAllListeners();
}
private void BackToGame()
{
// 关闭Setting面板
UIManager.Instance.HidePanel<SettingPanel>();
}
private void BackToMain()
{
// 关闭Setting面板
UIManager.Instance.HidePanel<SettingPanel>();
// 重启
GameManager.Instance.QuitGame();
}
private void Quit()
{
Application.Quit();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff78a14b28070864692582ecc5db824c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+75
View File
@@ -0,0 +1,75 @@
using AibisDream.Utility;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class StartPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => false;
#region
public void Show()
{
gameObject.SetActive(true);
}
public void Hide()
{
gameObject.SetActive(false);
}
#endregion
private void Awake()
{
RegisterButton();
}
private void RegisterButton()
{
// 开始界面按钮
var tabs = transform.Find("Tabs");
tabs.Find("Start").GetComponent<Button>().onClick.AddListener(StartNewGame);
tabs.Find("Select Level").GetComponent<Button>().onClick.AddListener(OpenLevelPanel);
tabs.Find("Load Save File").GetComponent<Button>().onClick.AddListener(OpenSaveFilePanel);
tabs.Find("Setting").GetComponent<Button>().onClick.AddListener(OpenSetting);
tabs.Find("Quit").GetComponent<Button>().onClick.AddListener(QuitApp);
// 打开链接
transform.Find("问卷").GetComponent<Button>().onClick.AddListener(() => Application.OpenURL(ConstRef.SurveyURL));
transform.Find("关注").GetComponent<Button>().onClick.AddListener(() => Application.OpenURL(ConstRef.QQURL));
}
#region
private void StartNewGame()
{
GameManager.Instance.StartNewGame();
}
private void OpenLevelPanel()
{
// TODO 打开选关面板
}
private void OpenSaveFilePanel()
{
UIManager.Instance.ShowPanel<SavesPanel>();
}
private void OpenSetting()
{
UIManager.Instance.ShowPanel<SettingPanel>();
}
private void QuitApp()
{
GameManager.Instance.QuitApp();
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9ba6256b10e589d478fc8c1910595417
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+2 -4
View File
@@ -1,5 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TMPro;
@@ -49,10 +47,10 @@ namespace AibisDream
// 隐藏UI
gameObject.SetActive(false);
// 开始游戏
GameLoopManager.Instance.StartWithSaveFile(saveFileName);
// GameLoopManager.Instance.StartWithSaveFile(saveFileName);
}
public void HideSaveFileUI()
private void HideSaveFileUI()
{
gameObject.SetActive(false);
}
+183
View File
@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using AibisDream.Framework;
using UnityEngine;
namespace AibisDream
{
public class UIManager : Kit.Singleton<UIManager>, IUIManager
{
#region
private Dictionary<Type, IUIPanel> _panelPool;
private readonly Stack<IUIPanel> _panelStack = new();
public RectTransform Canvas { get; private set; }
public Vector2 Resolution { get; set; }
public Camera UICamera { get; private set; }
public RectTransform DialogCanvas { get; private set; }
#endregion
public override void OnSingletonInit()
{
InitRefs();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (_panelStack.Count > 0)
{
var lastPanel = _panelStack.Peek();
HidePanel(lastPanel);
}
else
{
ShowPanel<SettingPanel>();
}
}
if (Input.GetKeyDown(KeyCode.C))
{
if (GetPanel<MainPanel>().IsOpen)
{
HidePanel<MainPanel>();
}
else
{
ShowPanel<MainPanel>();
}
}
}
private void InitRefs()
{
UICamera = transform.Find("UI Camera").GetComponent<Camera>();
// 获取Canvas
Canvas = transform.Find("UI Canvas").GetComponent<RectTransform>();
DialogCanvas = transform.Find("Dialog Canvas").GetComponent<RectTransform>();
// 获取Panel
var panels = Canvas.GetComponentsInChildren<IUIPanel>(true);
_panelPool = new Dictionary<Type, IUIPanel>();
foreach (var panel in panels)
{
_panelPool[panel.GetType()] = panel;
}
EnumEventSystem.Global.Register(GameLoopEnum.AppStart, OnAppStart);
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, OnGameStart);
EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, OnGameQuit);
}
private void OnAppStart()
{
// 游戏打开
ShowPanel<StartPanel>();
ShowPanel<PlayToolPanel>();
HidePanel<MainPanel>();
HidePanel<SettingPanel>();
HidePanel<RecordPanel>();
HidePanel<EndPanel>();
}
private void OnGameStart()
{
// 开始游戏
HidePanel<StartPanel>();
ShowPanel<MainPanel>();
}
private void OnGameQuit()
{
HidePanel<MainPanel>();
ShowPanel<StartPanel>();
}
public void ShowPanel<T>(Action<T> call = null) where T : class, IUIPanel
{
var type = typeof(T);
// 从缓存中检查panel
if (_panelPool.TryGetValue(type, out var panel))
{
if (panel.IsOpen) return;
if (panel.IsCloseable) _panelStack.Push(panel);
panel.Show();
call?.Invoke(panel as T);
}
else
{
Debug.Log($"panel {type} 未注册");
}
}
public void HidePanel<T>() where T : IUIPanel
{
var type = typeof(T);
// 从缓存中检查panel
if (_panelPool.TryGetValue(type, out var panel))
{
if (!panel.IsOpen) return;
if (panel.IsCloseable) _panelStack.Pop();
panel.Hide();
}
else
{
Debug.Log($"panel {type} 未注册");
}
}
private void HidePanel<T>(T panel) where T : IUIPanel
{
if (_panelPool.ContainsValue(panel))
{
if (!panel.IsOpen) return;
if (panel.IsCloseable) _panelStack.Pop();
panel.Hide();
}
else
{
Debug.Log($"panel {typeof(T)} 未注册");
}
}
public T GetPanel<T>() where T : class, IUIPanel
{
if (_panelPool.TryGetValue(typeof(T), out var panel))
{
return panel as T;
}
Debug.Log($"没有找到{typeof(T)}");
return null;
}
public static Vector3 GetDialogUIPos(Vector3 screenPos)
{
// 转换为UI坐标
RectTransformUtility.ScreenPointToLocalPointInRectangle(
Instance.DialogCanvas,
screenPos,
Instance.UICamera,
out Vector2 localPoint);
return localPoint;
}
}
public interface IUIManager
{
void ShowPanel<T>(Action<T> call = null) where T : class, IUIPanel;
void HidePanel<T>() where T : IUIPanel;
T GetPanel<T>() where T : class, IUIPanel;
RectTransform Canvas { get; }
Vector2 Resolution { get; set; }
// 还没想好要不要用栈
// UIPanel Pop();
// void Push<T>(T panel) where T : UIPanel;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0981e1188cb42a844b3b7b79a186bd39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+12
View File
@@ -0,0 +1,12 @@
using UnityEngine;
namespace AibisDream
{
public interface IUIPanel
{
public virtual void Show() { }
public virtual void Hide() { }
public bool IsOpen { get; }
public bool IsCloseable { get; }
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 714c1d8a65854c1fb1355f6ff2c6f670
timeCreated: 1743669973