using System; using System.Collections; using System.Collections.Generic; using AibisDream.Framework; using UnityEngine; using UnityEngine.UI; namespace AibisDream { public class CursorManager : MonoBehaviour { private const float DelayTime = 0.1f; [Header("指针图片")] public Sprite defaultCursor; public Sprite nextTalk, talking, option, interactive, holding, disable, eye; private Image _cursor; #region 状态相关 private Coroutine _switchCoroutine; private CursorState _curState = CursorState.Default; private bool _isTalking; [HideInInspector] public bool isInMenu; #endregion // 卸载时注销事件 private readonly List _unRegisters = new(); public void Awake() { InitRefs(); InitCursor(); } private void InitCursor() { Cursor.visible = false; SwitchCursor(defaultCursor); } private void OnEnable() { RegisterEvent(); } private void OnDisable() { // 注销所有事件 foreach (var eventUnRegister in _unRegisters) { eventUnRegister.UnRegister(); } _unRegisters.Clear(); } private void InitRefs() { _cursor = transform.Find("Cursor").GetComponent(); } private void RegisterEvent() { // 此处监听所有可能对鼠标状态产生影响的事件 RegisterDialogEvent(); RegisterTriggerEvent(); RegisterMenu(); } private void RegisterDialogEvent() { // 对话相关 _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineStart, OnLineStart)); _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShowed, () => SwitchCursor(nextTalk))); _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineEnd, OnLineEnd)); _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow)); _unRegisters.Add( EnumEventSystem.Global.Register(DialogEventEnum.OptionSelected, OnOptionSelect)); } private void RegisterTriggerEvent() { // 交互相关 _unRegisters.Add(EnumEventSystem.Global.Register(InteractionEventEnum.Start, OnInteractiveStart)); _unRegisters.Add(EnumEventSystem.Global.Register(InteractionEventEnum.End, OnInteractiveEnd)); _unRegisters.Add( EnumEventSystem.Global.Register(TriggerEnum.PointerEnter, OnPointerEnter)); _unRegisters.Add( EnumEventSystem.Global.Register(TriggerEnum.PointerExit, OnPointerExit)); _unRegisters.Add( EnumEventSystem.Global.Register(TriggerEnum.PointerDown, OnPointerDown)); _unRegisters.Add( EnumEventSystem.Global.Register(TriggerEnum.PointerUp, OnPointerUp)); } private void RegisterMenu() { _unRegisters.Add(EnumEventSystem.Global.Register(EventEnum.Menu, OnMenuChange)); } private void Update() { if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) { if (_isTalking && !isInMenu) { DialogController.Instance.JumpLine(); } } } private void LateUpdate() { // // 将虚拟指针与鼠标位置同步 // RectTransformUtility.ScreenPointToLocalPointInRectangle(_cursorCanvas, Input.mousePosition, // CameraKit.Instance.uiCamera, out var worldPos); _cursor.rectTransform.position = Input.mousePosition; // 在输入状态,要单独处理 } #region 对话相关 private void OnLineStart(DialogLine line) { _isTalking = true; SwitchCursor(talking); } private void OnLineEnd() { StopDelayCursor(); _switchCoroutine = StartCoroutine(DelayAction(() => { _isTalking = false; _cursor.sprite = defaultCursor; })); } private void OnOptionShow() { _isTalking = true; SwitchCursor(option); } private void OnOptionSelect(DialogLine line) { StopDelayCursor(); StartCoroutine(DelayAction(() => { _isTalking = false; _cursor.sprite = defaultCursor; })); } #endregion #region 交互相关 private void OnInteractiveStart() { _curState = CursorState.Interactive; if (EventSystemEx.Instance.pointerOverObj) { SwitchCursor(interactive); } } private void OnInteractiveEnd() { _curState = CursorState.Default; // 退出时把Cursor置为Default SwitchCursor(defaultCursor); } private void OnPointerEnter(IInteraction target) { if (_curState == CursorState.Interactive && !_isTalking) { // 如果不可交互,就显示不可交互的指针 SwitchCursor(target.IsActive ? interactive : disable); } } private void OnPointerExit(IInteraction target) { if (_curState == CursorState.Interactive && !_isTalking) { SwitchCursor(defaultCursor); } } private void OnPointerDown(IInteraction target) { if (_curState == CursorState.Interactive && !_isTalking) { SwitchCursor(target.IsActive ? holding : defaultCursor); } } private void OnPointerUp(IInteraction target) { if (_curState == CursorState.Interactive && !_isTalking) { // 如果松手时还在物体之上 SwitchCursor(EventSystemEx.Instance.holdingObj == target.GetGameObject() ? interactive : defaultCursor); } } #endregion #region 菜单打开 private void OnMenuChange(bool isMenuOpen) { isInMenu = isMenuOpen; } #endregion #region 指针切换 /// /// 直接切指针 /// /// 指针图片 private void SwitchCursor(Sprite sprite) { StopDelayCursor(); _cursor.sprite = sprite; } private void StopDelayCursor() { if (_switchCoroutine != null) { StopCoroutine(_switchCoroutine); _switchCoroutine = null; } } #endregion private static IEnumerator DelayAction(Action action) { yield return new WaitForSeconds(DelayTime); action.Invoke(); } } public enum CursorState { Default, Interactive, Eye } }