285 lines
8.2 KiB
C#
285 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using BriarQueen.Framework.Coordinators.Events;
|
|
using BriarQueen.Framework.Events.UI;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using VContainer;
|
|
|
|
namespace BriarQueen.Framework.Managers.UI
|
|
{
|
|
public sealed class UICursorService : MonoBehaviour
|
|
{
|
|
public enum CursorStyle
|
|
{
|
|
Default,
|
|
Interact,
|
|
Talk,
|
|
Pickup,
|
|
Inspect,
|
|
UseItem,
|
|
Travel,
|
|
Knife,
|
|
}
|
|
|
|
[Header("System Cursor")]
|
|
[SerializeField]
|
|
private bool _enableCustomCursor = true;
|
|
|
|
[SerializeField]
|
|
private bool _restoreDefaultCursorOnDisable = true;
|
|
|
|
[Header("Software Cursor")]
|
|
[SerializeField]
|
|
private RectTransform _virtualCursorTransform;
|
|
|
|
[SerializeField]
|
|
private Image _virtualCursorImage;
|
|
|
|
[Header("Styles")]
|
|
[SerializeField]
|
|
private CursorStyle _startingStyle = CursorStyle.Default;
|
|
|
|
[SerializeField]
|
|
private List<CursorStyleEntry> _styles = new();
|
|
|
|
private readonly Dictionary<CursorStyle, CursorStyleEntry> _styleMap = new();
|
|
|
|
private EventCoordinator _eventCoordinator;
|
|
|
|
private CursorStyle _currentStyle;
|
|
private CursorStyle _currentStyleOverride = CursorStyle.Default;
|
|
private bool _isStyleOverridden;
|
|
|
|
private Texture2D _currentTexture;
|
|
private Vector2 _currentHotspot;
|
|
private CursorMode _currentMode;
|
|
|
|
private bool _useVirtualCursor;
|
|
|
|
public CursorStyleEntry CurrentStyleEntry => _styleMap[_currentStyle];
|
|
|
|
[Inject]
|
|
private void Construct(EventCoordinator eventCoordinator)
|
|
{
|
|
_eventCoordinator = eventCoordinator;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
BuildStyleMap();
|
|
_currentStyle = _startingStyle;
|
|
_currentStyleOverride = CursorStyle.Default;
|
|
_isStyleOverridden = false;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
_eventCoordinator?.Subscribe<CursorStyleChangeEvent>(OnCursorStyleChangeEvent);
|
|
_eventCoordinator?.Subscribe<OverrideCursorStyleChangeEvent>(OnOverrideCursorStyleChangeEvent);
|
|
|
|
ApplyCurrentEffectiveStyle();
|
|
ApplyCursorModeVisuals();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
_eventCoordinator?.Unsubscribe<CursorStyleChangeEvent>(OnCursorStyleChangeEvent);
|
|
_eventCoordinator?.Unsubscribe<OverrideCursorStyleChangeEvent>(OnOverrideCursorStyleChangeEvent);
|
|
|
|
if (_restoreDefaultCursorOnDisable)
|
|
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
BuildStyleMap();
|
|
}
|
|
|
|
public void SetUseVirtualCursor(bool useVirtualCursor)
|
|
{
|
|
if (_useVirtualCursor == useVirtualCursor)
|
|
return;
|
|
|
|
_useVirtualCursor = useVirtualCursor;
|
|
ApplyCursorModeVisuals();
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
public void SetVirtualCursorPosition(Vector2 screenPosition)
|
|
{
|
|
if (!_useVirtualCursor || _virtualCursorTransform == null)
|
|
return;
|
|
|
|
_virtualCursorTransform.position = screenPosition;
|
|
}
|
|
|
|
public void SetStyle(CursorStyle style)
|
|
{
|
|
_currentStyle = style;
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
public void SetOverrideStyle(CursorStyle style)
|
|
{
|
|
if (style == CursorStyle.Default)
|
|
{
|
|
ClearOverrideStyle();
|
|
return;
|
|
}
|
|
|
|
_isStyleOverridden = true;
|
|
_currentStyleOverride = style;
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
public void ClearOverrideStyle()
|
|
{
|
|
_isStyleOverridden = false;
|
|
_currentStyleOverride = CursorStyle.Default;
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
public void ResetToDefault()
|
|
{
|
|
_currentStyle = CursorStyle.Default;
|
|
ClearOverrideStyle();
|
|
}
|
|
|
|
private void OnCursorStyleChangeEvent(CursorStyleChangeEvent evt)
|
|
{
|
|
_currentStyle = evt.Style;
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
private void OnOverrideCursorStyleChangeEvent(OverrideCursorStyleChangeEvent evt)
|
|
{
|
|
if (evt.Style == CursorStyle.Default)
|
|
{
|
|
ClearOverrideStyle();
|
|
return;
|
|
}
|
|
|
|
_isStyleOverridden = true;
|
|
_currentStyleOverride = evt.Style;
|
|
ApplyCurrentEffectiveStyle();
|
|
}
|
|
|
|
private void ApplyCursorModeVisuals()
|
|
{
|
|
Cursor.visible = !_useVirtualCursor;
|
|
|
|
if (_virtualCursorImage != null)
|
|
_virtualCursorImage.enabled = _useVirtualCursor;
|
|
}
|
|
|
|
private void ApplyCurrentEffectiveStyle()
|
|
{
|
|
var style = GetEffectiveStyle();
|
|
|
|
if (_useVirtualCursor)
|
|
{
|
|
ApplyVirtualCursorStyle(style);
|
|
}
|
|
else
|
|
{
|
|
ApplySystemCursorStyle(style);
|
|
}
|
|
}
|
|
|
|
private CursorStyle GetEffectiveStyle()
|
|
{
|
|
return _isStyleOverridden ? _currentStyleOverride : _currentStyle;
|
|
}
|
|
|
|
private void ApplyVirtualCursorStyle(CursorStyle style)
|
|
{
|
|
if (_virtualCursorImage == null)
|
|
return;
|
|
|
|
if (!_styleMap.TryGetValue(style, out var entry) || entry.Texture == null)
|
|
{
|
|
if (!_styleMap.TryGetValue(CursorStyle.Default, out entry) || entry.Texture == null)
|
|
return;
|
|
}
|
|
|
|
var rect = new Rect(0, 0, entry.Texture.width, entry.Texture.height);
|
|
var pivot = new Vector2(0.5f, 0.5f);
|
|
_virtualCursorImage.sprite = Sprite.Create(entry.Texture, rect, pivot);
|
|
}
|
|
|
|
private void ApplySystemCursorStyle(CursorStyle style)
|
|
{
|
|
if (!_enableCustomCursor)
|
|
return;
|
|
|
|
if (!_styleMap.TryGetValue(style, out var entry) || entry.Texture == null)
|
|
{
|
|
if (_styleMap.TryGetValue(CursorStyle.Default, out var defaultEntry) && defaultEntry.Texture != null)
|
|
{
|
|
entry = defaultEntry;
|
|
}
|
|
else
|
|
{
|
|
Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
|
|
CacheApplied(null, Vector2.zero, CursorMode.Auto);
|
|
return;
|
|
}
|
|
}
|
|
|
|
var hotspot = entry.Hotspot;
|
|
|
|
if (entry.Texture != null && entry.HotspotIsNormalized)
|
|
{
|
|
hotspot = new Vector2(
|
|
hotspot.x * entry.Texture.width,
|
|
hotspot.y * entry.Texture.height);
|
|
}
|
|
|
|
if (IsSameAsCurrent(entry.Texture, hotspot, entry.Mode))
|
|
return;
|
|
|
|
Cursor.SetCursor(entry.Texture, hotspot, entry.Mode);
|
|
CacheApplied(entry.Texture, hotspot, entry.Mode);
|
|
}
|
|
|
|
private bool IsSameAsCurrent(Texture2D texture, Vector2 hotspot, CursorMode mode)
|
|
{
|
|
return _currentTexture == texture &&
|
|
_currentHotspot == hotspot &&
|
|
_currentMode == mode;
|
|
}
|
|
|
|
private void CacheApplied(Texture2D texture, Vector2 hotspot, CursorMode mode)
|
|
{
|
|
_currentTexture = texture;
|
|
_currentHotspot = hotspot;
|
|
_currentMode = mode;
|
|
}
|
|
|
|
private void BuildStyleMap()
|
|
{
|
|
_styleMap.Clear();
|
|
|
|
if (_styles == null)
|
|
return;
|
|
|
|
for (var i = 0; i < _styles.Count; i++)
|
|
{
|
|
var entry = _styles[i];
|
|
_styleMap[entry.Style] = entry;
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public struct CursorStyleEntry
|
|
{
|
|
public CursorStyle Style;
|
|
public Texture2D Texture;
|
|
public Vector2 Hotspot;
|
|
public CursorMode Mode;
|
|
public bool HotspotIsNormalized;
|
|
public Vector2 TooltipOffset;
|
|
}
|
|
}
|
|
} |