using System; using System.Collections; using System.Collections.Generic; using AibisDream.Framework; using AibisDream.Kit; using UnityEngine; using UnityEngine.UI; namespace AibisDream { public class CursorManager : Singleton { private const float DelayTime = 0.1f; [Header("指针图片")] public Sprite defaultCursor; public Sprite nextTalk, talking, option, interactive, holding, disable; private Image _cursor; private Sprite _cursorCache; private CursorState _stateCache; #region 状态相关 private Coroutine _switchCoroutine; private CursorState _curState = CursorState.Default; private bool _isTalking; private bool _isPaused; #endregion // 卸载时注销事件 private readonly List _unRegisters = new(); public override void OnSingletonInit() { 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() { // 此处监听所有可能对鼠标状态产生影响的事件 RegisterGameEvent(); RegisterDialogEvent(); RegisterTriggerEvent(); } private void RegisterGameEvent() { _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 OnUnPauseGame() { _cursor.sprite = _cursorCache; _cursorCache = null; _curState = _stateCache; _stateCache = CursorState.Default; _isPaused = false; } private void OnPauseGame() { _cursorCache = _cursor.sprite; _cursor.sprite = defaultCursor; _stateCache = _curState; _curState = CursorState.Default; _isPaused = true; } private void OnGameQuit() { _cursor.sprite = defaultCursor; _cursorCache = null; _curState = CursorState.Default; _stateCache = CursorState.Default; _isPaused = false; } private void RegisterDialogEvent() { // 对话相关 _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineStart, OnLineStart)); _unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, () => 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 Update() { if (_isPaused) { return; } if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) { if (_isTalking) { 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(DialogText 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(DialogText line) { StopDelayCursor(); _switchCoroutine = 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 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, Dialog, Menu } }