Update
This commit is contained in:
@@ -12,12 +12,13 @@ namespace Hallucinate.UI
|
||||
|
||||
private VisualElement _logo;
|
||||
private VisualElement _ribbon;
|
||||
private VisualElement _virtualCursor;
|
||||
private VisualElement _logoSpace;
|
||||
|
||||
private float _lastInteractionTime;
|
||||
private const float IDLE_TIMEOUT = 5.0f;
|
||||
|
||||
private Tween _pulseTween;
|
||||
private Tween _rotationTween;
|
||||
|
||||
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
|
||||
{
|
||||
@@ -25,89 +26,117 @@ namespace Hallucinate.UI
|
||||
|
||||
_logo = root.Q<VisualElement>("Logo");
|
||||
_ribbon = root.Q<VisualElement>("Ribbon");
|
||||
_virtualCursor = root.Q<VisualElement>("VirtualCursor");
|
||||
_logoSpace = root.Q<VisualElement>("LogoSpace");
|
||||
|
||||
if (_logo == null)
|
||||
{
|
||||
Debug.LogError($"[MainMenuController] Element 'Logo' not found in UXML! Root children: {root.childCount}");
|
||||
Debug.LogError($"[MainMenuController] Element 'Logo' not found in UXML!");
|
||||
return;
|
||||
}
|
||||
|
||||
_logo.RegisterCallback<PointerDownEvent>(OnLogoClicked);
|
||||
ResetLogoPosition();
|
||||
_logo.RegisterCallback<ClickEvent>(OnLogoClicked);
|
||||
|
||||
// Bind Buttons with null checks
|
||||
var settingsBtn = root.Q<Button>("SettingsBtn");
|
||||
if (settingsBtn != null) settingsBtn.clicked += () => uiManager.Push<SettingsController>();
|
||||
|
||||
var joinBtn = root.Q<Button>("JoinBtn");
|
||||
if (joinBtn != null) joinBtn.clicked += () => uiManager.Push<LobbyController>();
|
||||
|
||||
var createBtn = root.Q<Button>("CreateBtn");
|
||||
if (createBtn != null) createBtn.clicked += () => uiManager.Push<LobbyController>();
|
||||
|
||||
var profileBtn = root.Q<Button>("ProfileBtn");
|
||||
if (profileBtn != null) profileBtn.clicked += () => uiManager.Push<ProfileController>();
|
||||
|
||||
var exitBtn = root.Q<Button>("ExitBtn");
|
||||
if (exitBtn != null) exitBtn.clicked += () => Application.Quit();
|
||||
// Bind Buttons
|
||||
root.Q<Button>("SettingsBtn").clicked += () => uiManager.Push<SettingsController>();
|
||||
root.Q<Button>("JoinBtn").clicked += () => uiManager.Push<LobbyController>();
|
||||
root.Q<Button>("CreateBtn").clicked += () => uiManager.Push<LobbyController>();
|
||||
root.Q<Button>("ProfileBtn").clicked += () => uiManager.Push<ProfileController>();
|
||||
root.Q<Button>("ExitBtn").clicked += () => Application.Quit();
|
||||
|
||||
StartPulse();
|
||||
_lastInteractionTime = Time.time;
|
||||
}
|
||||
|
||||
private void ResetLogoPosition()
|
||||
{
|
||||
_logo.style.left = (Screen.width / 2f) - 100;
|
||||
_logo.style.top = (Screen.height / 2f) - 100;
|
||||
_logo.style.width = 200;
|
||||
_logo.style.height = 200;
|
||||
}
|
||||
|
||||
public void SetGameIcon(Texture2D icon)
|
||||
{
|
||||
if (icon == null || _logo == null) return;
|
||||
_logo.style.backgroundImage = icon;
|
||||
|
||||
var radius = new StyleLength(new Length(50, LengthUnit.Percent));
|
||||
_logo.style.borderTopLeftRadius = radius;
|
||||
_logo.style.borderTopRightRadius = radius;
|
||||
_logo.style.borderBottomLeftRadius = radius;
|
||||
_logo.style.borderBottomRightRadius = radius;
|
||||
_logo.style.overflow = Overflow.Hidden;
|
||||
|
||||
var label = _logo.Q<Label>();
|
||||
if (label != null) label.style.display = DisplayStyle.None;
|
||||
|
||||
if (_rotationTween.isAlive) _rotationTween.Stop();
|
||||
_rotationTween = Tween.Custom(0f, 360f, duration: 4f, cycles: -1, ease: Ease.Linear,
|
||||
onValueChange: val => _logo.style.rotate = new StyleRotate(new Rotate(Angle.Degrees(val))));
|
||||
}
|
||||
|
||||
public override async Task PlayTransitionIn()
|
||||
{
|
||||
await base.PlayTransitionIn();
|
||||
UnityEngine.Cursor.visible = false;
|
||||
Show();
|
||||
// Đảm bảo chuột hệ thống luôn hiện
|
||||
UnityEngine.Cursor.visible = true;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task PlayTransitionOut()
|
||||
{
|
||||
UnityEngine.Cursor.visible = true;
|
||||
if (_rotationTween.isAlive) _rotationTween.Stop();
|
||||
await base.PlayTransitionOut();
|
||||
}
|
||||
|
||||
private void StartPulse()
|
||||
{
|
||||
// Use Vector3.one * 1.1f for target scale
|
||||
_pulseTween = Tween.Scale(_logo.transform, Vector3.one * 1.1f, duration: 0.8f, cycles: -1, cycleMode: CycleMode.Yoyo, ease: Ease.InOutSine);
|
||||
}
|
||||
|
||||
private void OnLogoClicked(PointerDownEvent evt)
|
||||
private void OnLogoClicked(ClickEvent evt)
|
||||
{
|
||||
_lastInteractionTime = Time.time;
|
||||
|
||||
if (_currentState == MenuState.Idle)
|
||||
{
|
||||
TransitionToRibbon();
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = uiManager.Push<LobbyController>();
|
||||
}
|
||||
if (_currentState == MenuState.Idle) TransitionToRibbon();
|
||||
else _ = uiManager.Push<LobbyController>();
|
||||
}
|
||||
|
||||
private void TransitionToRibbon()
|
||||
private async void TransitionToRibbon()
|
||||
{
|
||||
_currentState = MenuState.Ribbon;
|
||||
|
||||
// Transition Logo using Custom tween for offset
|
||||
Tween.Custom(0f, -300f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.left = val);
|
||||
|
||||
_ribbon.style.display = DisplayStyle.Flex;
|
||||
_ribbon.style.opacity = 0;
|
||||
Tween.Custom(0f, 1f, duration: 0.3f, onValueChange: val => _ribbon.style.opacity = val);
|
||||
|
||||
await Task.Yield();
|
||||
|
||||
Rect targetBounds = _logoSpace.worldBound;
|
||||
|
||||
// Fade in Ribbon
|
||||
Tween.Custom(0f, 1f, duration: 0.5f, onValueChange: val => _ribbon.style.opacity = val);
|
||||
Tween.Custom(_logo.style.left.value.value, targetBounds.x, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.left = val);
|
||||
|
||||
Tween.Custom(_logo.style.top.value.value, targetBounds.y - 35, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.top = val);
|
||||
|
||||
Tween.Custom(_logo.style.width.value.value, 120f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.width = val);
|
||||
|
||||
Tween.Custom(_logo.style.height.value.value, 120f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.height = val);
|
||||
}
|
||||
|
||||
private void TransitionToIdle()
|
||||
{
|
||||
_currentState = MenuState.Idle;
|
||||
|
||||
Tween.Custom(-300f, 0f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
|
||||
float targetX = (Screen.width / 2f) - 100;
|
||||
float targetY = (Screen.height / 2f) - 100;
|
||||
|
||||
Tween.Custom(_logo.style.left.value.value, targetX, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.left = val);
|
||||
Tween.Custom(_logo.style.top.value.value, targetY, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.top = val);
|
||||
Tween.Custom(_logo.style.width.value.value, 200f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.width = val);
|
||||
Tween.Custom(_logo.style.height.value.value, 200f, duration: 0.5f, ease: Ease.OutQuad,
|
||||
onValueChange: val => _logo.style.height = val);
|
||||
|
||||
Tween.Custom(1f, 0f, duration: 0.5f, onValueChange: val => _ribbon.style.opacity = val)
|
||||
.OnComplete(() => _ribbon.style.display = DisplayStyle.None);
|
||||
@@ -115,32 +144,15 @@ namespace Hallucinate.UI
|
||||
|
||||
public void Update()
|
||||
{
|
||||
UpdateVirtualCursor();
|
||||
|
||||
if (_currentState == MenuState.Ribbon)
|
||||
if (_currentState == MenuState.Ribbon && Time.time - _lastInteractionTime > IDLE_TIMEOUT)
|
||||
{
|
||||
if (Time.time - _lastInteractionTime > IDLE_TIMEOUT)
|
||||
{
|
||||
TransitionToIdle();
|
||||
}
|
||||
TransitionToIdle();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVirtualCursor()
|
||||
private void StartPulse()
|
||||
{
|
||||
if (_virtualCursor == null) return;
|
||||
|
||||
Vector2 mousePos = Input.mousePosition;
|
||||
float x = mousePos.x;
|
||||
float y = Screen.height - mousePos.y;
|
||||
|
||||
if (_currentState == MenuState.Ribbon)
|
||||
{
|
||||
y = Screen.height / 2f + 50;
|
||||
}
|
||||
|
||||
_virtualCursor.style.left = x - _virtualCursor.layout.width / 2;
|
||||
_virtualCursor.style.top = y - _virtualCursor.layout.height / 2;
|
||||
_pulseTween = Tween.Scale(_logo.transform, Vector3.one * 1.1f, duration: 0.8f, cycles: -1, cycleMode: CycleMode.Yoyo, ease: Ease.InOutSine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Hallucinate.UI
|
||||
{
|
||||
@@ -17,6 +20,9 @@ namespace Hallucinate.UI
|
||||
private readonly Dictionary<Type, BaseUIController> _controllers = new Dictionary<Type, BaseUIController>();
|
||||
private readonly Stack<BaseUIController> _history = new Stack<BaseUIController>();
|
||||
|
||||
[Header("Game Metadata")]
|
||||
[SerializeField] private Texture2D gameIcon;
|
||||
|
||||
[Header("UI Templates")]
|
||||
[SerializeField] private VisualTreeAsset mainMenuTemplate;
|
||||
[SerializeField] private VisualTreeAsset lobbyTemplate;
|
||||
@@ -48,6 +54,14 @@ namespace Hallucinate.UI
|
||||
|
||||
_uiDocument = GetComponent<UIDocument>();
|
||||
_rootElement = _uiDocument.rootVisualElement;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (gameIcon == null)
|
||||
{
|
||||
var icons = PlayerSettings.GetIconsForTargetGroup(BuildTargetGroup.Unknown);
|
||||
if (icons != null && icons.Length > 0) gameIcon = icons[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
InitializeControllers();
|
||||
}
|
||||
@@ -55,6 +69,11 @@ namespace Hallucinate.UI
|
||||
private void InitializeControllers()
|
||||
{
|
||||
_mainMenuController = RegisterController<MainMenuController>(mainMenuTemplate);
|
||||
if (_mainMenuController != null && gameIcon != null)
|
||||
{
|
||||
_mainMenuController.SetGameIcon(gameIcon);
|
||||
}
|
||||
|
||||
_lobbyController = RegisterController<LobbyController>(lobbyTemplate);
|
||||
_profileController = RegisterController<ProfileController>(profileTemplate);
|
||||
_settingsController = RegisterController<SettingsController>(settingsTemplate);
|
||||
@@ -120,7 +139,5 @@ namespace Hallucinate.UI
|
||||
var previousScreen = _history.Peek();
|
||||
await previousScreen.PlayTransitionIn();
|
||||
}
|
||||
|
||||
// Custom Inspector features can be added here with [ContextMenu] or CustomEditor
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user