First commit for private source control. Older commits available on Github.
This commit is contained in:
285
Assets/Scripts/Framework/Managers/UI/UICursorService.cs
Normal file
285
Assets/Scripts/Framework/Managers/UI/UICursorService.cs
Normal file
@@ -0,0 +1,285 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user