Update
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using PrimeTween;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
@@ -16,6 +17,7 @@ namespace Hallucinate.UI
|
||||
|
||||
private UIDocument _uiDocument;
|
||||
private VisualElement _rootElement;
|
||||
private VisualElement _cursorLayer; // Lớp trên cùng chứa trail và ripples
|
||||
|
||||
private readonly Dictionary<Type, BaseUIController> _controllers = new Dictionary<Type, BaseUIController>();
|
||||
private readonly Stack<BaseUIController> _history = new Stack<BaseUIController>();
|
||||
@@ -23,6 +25,13 @@ namespace Hallucinate.UI
|
||||
[Header("Game Metadata")]
|
||||
[SerializeField] private Texture2D gameIcon;
|
||||
|
||||
[Header("Cursor & Effects Settings")]
|
||||
[SerializeField] private Sprite cursorTrailSprite;
|
||||
[SerializeField, Range(10f, 100f)] private float cursorSize = 30f;
|
||||
[SerializeField, Range(5, 30)] private int trailLength = 15;
|
||||
[SerializeField] private bool enableRipples = true;
|
||||
[SerializeField] private Color rippleColor = new Color(1, 1, 1, 0.5f);
|
||||
|
||||
[Header("UI Templates")]
|
||||
[SerializeField] private VisualTreeAsset mainMenuTemplate;
|
||||
[SerializeField] private VisualTreeAsset lobbyTemplate;
|
||||
@@ -31,6 +40,7 @@ namespace Hallucinate.UI
|
||||
[SerializeField] private VisualTreeAsset hudTemplate;
|
||||
|
||||
private MainMenuController _mainMenuController;
|
||||
private List<VisualElement> _trailSegments = new List<VisualElement>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -48,6 +58,20 @@ namespace Hallucinate.UI
|
||||
_uiDocument = GetComponent<UIDocument>();
|
||||
_rootElement = _uiDocument.rootVisualElement;
|
||||
|
||||
// Tạo lớp Cursor trên cùng
|
||||
_cursorLayer = new VisualElement();
|
||||
_cursorLayer.name = "CursorLayer";
|
||||
_cursorLayer.style.position = Position.Absolute;
|
||||
_cursorLayer.style.width = Length.Percent(100);
|
||||
_cursorLayer.style.height = Length.Percent(100);
|
||||
_cursorLayer.pickingMode = PickingMode.Ignore;
|
||||
_rootElement.Add(_cursorLayer);
|
||||
|
||||
SetupCursorTrail();
|
||||
|
||||
// Đăng ký ripple toàn cục
|
||||
_rootElement.RegisterCallback<PointerDownEvent>(OnGlobalClick, TrickleDown.TrickleDown);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (gameIcon == null)
|
||||
{
|
||||
@@ -59,6 +83,91 @@ namespace Hallucinate.UI
|
||||
InitializeControllers();
|
||||
}
|
||||
|
||||
private void SetupCursorTrail()
|
||||
{
|
||||
if (cursorTrailSprite == null) return;
|
||||
|
||||
for (int i = 0; i < trailLength; i++)
|
||||
{
|
||||
var segment = new VisualElement();
|
||||
segment.style.position = Position.Absolute;
|
||||
segment.style.width = cursorSize;
|
||||
segment.style.height = cursorSize;
|
||||
segment.style.backgroundImage = new StyleBackground(cursorTrailSprite);
|
||||
segment.style.opacity = 1f - ((float)i / trailLength);
|
||||
segment.style.scale = new StyleScale(new Vector2(1f - ((float)i / trailLength), 1f - ((float)i / trailLength)));
|
||||
segment.pickingMode = PickingMode.Ignore;
|
||||
|
||||
_cursorLayer.Add(segment);
|
||||
_trailSegments.Add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGlobalClick(PointerDownEvent evt)
|
||||
{
|
||||
if (!enableRipples) return;
|
||||
|
||||
var ripple = new VisualElement();
|
||||
ripple.style.position = Position.Absolute;
|
||||
ripple.style.width = cursorSize;
|
||||
ripple.style.height = cursorSize;
|
||||
ripple.style.borderTopLeftRadius = cursorSize;
|
||||
ripple.style.borderTopRightRadius = cursorSize;
|
||||
ripple.style.borderBottomLeftRadius = cursorSize;
|
||||
ripple.style.borderBottomRightRadius = cursorSize;
|
||||
ripple.style.borderTopColor = rippleColor;
|
||||
ripple.style.borderBottomColor = rippleColor;
|
||||
ripple.style.borderLeftColor = rippleColor;
|
||||
ripple.style.borderRightColor = rippleColor;
|
||||
ripple.style.borderTopWidth = 2;
|
||||
ripple.style.borderBottomWidth = 2;
|
||||
ripple.style.borderLeftWidth = 2;
|
||||
ripple.style.borderRightWidth = 2;
|
||||
|
||||
ripple.style.left = evt.localPosition.x - (cursorSize / 2);
|
||||
ripple.style.top = evt.localPosition.y - (cursorSize / 2);
|
||||
ripple.pickingMode = PickingMode.Ignore;
|
||||
|
||||
_cursorLayer.Add(ripple);
|
||||
|
||||
// Hiệu ứng Ripple: To ra và nhạt dần (Sửa lỗi dùng Vector3 thay vì float)
|
||||
Tween.Scale(ripple.transform, Vector3.one * 3f, duration: 0.5f, ease: Ease.OutQuad);
|
||||
Tween.Custom(1f, 0f, duration: 0.5f, onValueChange: val => ripple.style.opacity = val)
|
||||
.OnComplete(() => ripple.RemoveFromHierarchy());
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_mainMenuController?.Update();
|
||||
UpdateTrail();
|
||||
}
|
||||
|
||||
private void UpdateTrail()
|
||||
{
|
||||
if (_trailSegments.Count == 0) return;
|
||||
|
||||
Vector2 mousePos = Input.mousePosition;
|
||||
Vector2 uiPos = new Vector2(mousePos.x, Screen.height - mousePos.y);
|
||||
|
||||
// Segment đầu tiên đi theo chuột
|
||||
_trailSegments[0].style.left = uiPos.x - (cursorSize / 2);
|
||||
_trailSegments[0].style.top = uiPos.y - (cursorSize / 2);
|
||||
|
||||
// Các segment sau đuổi theo segment trước
|
||||
for (int i = 1; i < _trailSegments.Count; i++)
|
||||
{
|
||||
float targetX = _trailSegments[i - 1].resolvedStyle.left;
|
||||
float targetY = _trailSegments[i - 1].resolvedStyle.top;
|
||||
|
||||
float currX = _trailSegments[i].resolvedStyle.left;
|
||||
float currY = _trailSegments[i].resolvedStyle.top;
|
||||
|
||||
// Nội suy để mượt mà (Lerp)
|
||||
_trailSegments[i].style.left = Mathf.Lerp(currX, targetX, Time.deltaTime * 20f);
|
||||
_trailSegments[i].style.top = Mathf.Lerp(currY, targetY, Time.deltaTime * 20f);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeControllers()
|
||||
{
|
||||
_mainMenuController = RegisterController<MainMenuController>(mainMenuTemplate);
|
||||
@@ -72,7 +181,6 @@ namespace Hallucinate.UI
|
||||
RegisterController<SettingsController>(settingsTemplate);
|
||||
RegisterController<HUDController>(hudTemplate);
|
||||
|
||||
// Khởi động màn hình đầu tiên
|
||||
_ = Push<MainMenuController>();
|
||||
}
|
||||
|
||||
@@ -85,9 +193,12 @@ namespace Hallucinate.UI
|
||||
instance.style.position = Position.Absolute;
|
||||
instance.style.width = Length.Percent(100);
|
||||
instance.style.height = Length.Percent(100);
|
||||
instance.style.display = DisplayStyle.None; // Ẩn mặc định
|
||||
instance.style.display = DisplayStyle.None;
|
||||
_rootElement.Add(instance);
|
||||
|
||||
// Luôn đảm bảo CursorLayer nằm trên cùng sau khi add màn hình mới
|
||||
_cursorLayer.BringToFront();
|
||||
|
||||
var controller = new T();
|
||||
controller.Initialize(instance, this);
|
||||
_controllers[typeof(T)] = controller;
|
||||
@@ -95,41 +206,23 @@ namespace Hallucinate.UI
|
||||
return controller;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_mainMenuController?.Update();
|
||||
// Update các controller khác nếu cần
|
||||
}
|
||||
|
||||
public async Task Push<T>() where T : BaseUIController
|
||||
{
|
||||
if (!_controllers.TryGetValue(typeof(T), out var newScreen)) return;
|
||||
|
||||
// Nếu màn hình mới chính là màn hình đang hiện, không làm gì cả
|
||||
if (_history.Count > 0 && _history.Peek() == newScreen) return;
|
||||
|
||||
if (_history.Count > 0)
|
||||
{
|
||||
var currentScreen = _history.Peek();
|
||||
await currentScreen.PlayTransitionOut();
|
||||
}
|
||||
if (_history.Count > 0) await _history.Peek().PlayTransitionOut();
|
||||
|
||||
_history.Push(newScreen);
|
||||
await newScreen.PlayTransitionIn();
|
||||
_cursorLayer.BringToFront(); // Giữ trail luôn trên cùng
|
||||
}
|
||||
|
||||
public async Task Pop()
|
||||
{
|
||||
if (_history.Count <= 1) return;
|
||||
|
||||
var currentScreen = _history.Pop();
|
||||
await currentScreen.PlayTransitionOut();
|
||||
|
||||
if (_history.Count > 0)
|
||||
{
|
||||
var previousScreen = _history.Peek();
|
||||
await previousScreen.PlayTransitionIn();
|
||||
}
|
||||
await _history.Pop().PlayTransitionOut();
|
||||
if (_history.Count > 0) await _history.Peek().PlayTransitionIn();
|
||||
_cursorLayer.BringToFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user