Files
BABA_YAGA/Assets/Scripts/UI/MainMenuController.cs

208 lines
7.8 KiB
C#
Raw Normal View History

2026-04-25 18:20:16 +07:00
using UnityEngine;
using UnityEngine.UIElements;
2026-04-28 00:07:42 +07:00
using PrimeTween;
using System.Threading.Tasks;
2026-04-25 18:20:16 +07:00
2026-04-28 00:07:42 +07:00
namespace Hallucinate.UI
2026-04-25 18:20:16 +07:00
{
2026-04-28 00:07:42 +07:00
public class MainMenuController : BaseUIController
2026-04-25 18:20:16 +07:00
{
2026-04-28 00:07:42 +07:00
public enum MenuState { Idle, Ribbon }
private MenuState _currentState = MenuState.Idle;
2026-04-26 04:39:59 +07:00
private VisualElement _logo;
private VisualElement _ribbon;
2026-04-28 10:11:28 +07:00
private VisualElement _logoSpace;
2026-04-26 05:20:47 +07:00
private float _lastInteractionTime;
2026-04-28 00:07:42 +07:00
private const float IDLE_TIMEOUT = 5.0f;
2026-04-29 01:04:28 +07:00
private bool _isFirstLoad = true;
2026-04-25 18:20:16 +07:00
2026-04-28 00:07:42 +07:00
private Tween _pulseTween;
2026-04-28 10:11:28 +07:00
private Tween _rotationTween;
2026-04-28 10:44:22 +07:00
private Texture2D _currentIcon;
2026-04-26 04:39:59 +07:00
2026-04-28 00:07:42 +07:00
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
base.Initialize(uxmlRoot, manager);
2026-04-26 04:39:59 +07:00
2026-04-28 00:07:42 +07:00
_logo = root.Q<VisualElement>("Logo");
_ribbon = root.Q<VisualElement>("Ribbon");
2026-04-28 10:11:28 +07:00
_logoSpace = root.Q<VisualElement>("LogoSpace");
2026-04-25 18:20:16 +07:00
2026-04-28 00:07:42 +07:00
if (_logo == null)
2026-04-27 15:48:17 +07:00
{
2026-04-28 10:11:28 +07:00
Debug.LogError($"[MainMenuController] Element 'Logo' not found in UXML!");
2026-04-28 00:07:42 +07:00
return;
2026-04-27 15:48:17 +07:00
}
2026-04-28 10:11:28 +07:00
_logo.RegisterCallback<ClickEvent>(OnLogoClicked);
2026-04-26 05:20:47 +07:00
2026-04-28 13:07:52 +07:00
var settingsBtn = root.Q<Button>("SettingsBtn");
if (settingsBtn != null) settingsBtn.clicked += () => uiManager.ToggleSettings();
2026-04-29 01:04:28 +07:00
root.Q<Button>("JoinBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("CreateBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("ProfileBtn").clicked += async () => await uiManager.Push<ProfileController>();
2026-04-28 10:11:28 +07:00
root.Q<Button>("ExitBtn").clicked += () => Application.Quit();
2026-04-26 05:20:47 +07:00
2026-04-28 10:44:22 +07:00
ResetLogoPosition();
2026-04-28 00:07:42 +07:00
StartPulse();
_lastInteractionTime = Time.time;
2026-04-26 05:20:47 +07:00
}
2026-04-28 10:11:28 +07:00
private void ResetLogoPosition()
2026-04-26 05:20:47 +07:00
{
2026-04-28 10:25:34 +07:00
if (_logo == null) return;
2026-04-28 10:44:22 +07:00
_logo.style.translate = new StyleTranslate(new Translate(0, 0));
2026-04-28 10:11:28 +07:00
_logo.style.left = (Screen.width / 2f) - 100;
_logo.style.top = (Screen.height / 2f) - 100;
_logo.style.width = 200;
_logo.style.height = 200;
2026-04-26 05:20:47 +07:00
}
2026-04-28 10:11:28 +07:00
public void SetGameIcon(Texture2D icon)
{
if (icon == null || _logo == null) return;
2026-04-28 10:44:22 +07:00
_currentIcon = icon;
2026-04-28 10:11:28 +07:00
_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;
2026-04-28 10:44:22 +07:00
StartRotation();
}
private void StartRotation()
{
if (_currentIcon == null) return;
2026-04-28 10:11:28 +07:00
if (_rotationTween.isAlive) _rotationTween.Stop();
2026-04-28 10:44:22 +07:00
2026-04-29 01:04:28 +07:00
_rotationTween = Tween.Custom(0f, 360f, duration: 4f,
onValueChange: val => _logo.style.rotate = new StyleRotate(new Rotate(Angle.Degrees(val))),
cycles: -1,
ease: Ease.Linear);
2026-04-28 10:11:28 +07:00
}
public override async Task PlayTransitionIn()
2026-04-26 04:39:59 +07:00
{
2026-04-28 10:44:22 +07:00
_lastInteractionTime = Time.time;
2026-04-28 10:25:34 +07:00
_currentState = MenuState.Idle;
ResetLogoPosition();
2026-04-28 10:44:22 +07:00
2026-04-28 10:25:34 +07:00
if (_ribbon != null)
{
_ribbon.style.display = DisplayStyle.None;
_ribbon.style.opacity = 0;
}
2026-04-28 10:44:22 +07:00
StartRotation();
2026-04-28 10:25:34 +07:00
await base.PlayTransitionIn();
2026-04-29 01:04:28 +07:00
if (!_isFirstLoad) TransitionToRibbon();
else _isFirstLoad = false;
2026-04-28 00:07:42 +07:00
}
2026-04-27 13:27:40 +07:00
2026-04-28 10:11:28 +07:00
public override async Task PlayTransitionOut()
2026-04-28 00:07:42 +07:00
{
2026-04-28 10:11:28 +07:00
if (_rotationTween.isAlive) _rotationTween.Stop();
await base.PlayTransitionOut();
2026-04-27 15:48:17 +07:00
}
2026-04-29 01:04:28 +07:00
private async void OnLogoClicked(ClickEvent evt)
2026-04-27 15:48:17 +07:00
{
2026-04-28 00:07:42 +07:00
_lastInteractionTime = Time.time;
2026-04-28 10:11:28 +07:00
if (_currentState == MenuState.Idle) TransitionToRibbon();
2026-04-29 01:04:28 +07:00
else await uiManager.Push<LobbyController>();
2026-04-26 04:39:59 +07:00
}
2026-04-28 10:44:22 +07:00
private void TransitionToRibbon()
2026-04-26 05:20:47 +07:00
{
2026-04-28 10:44:22 +07:00
if (_currentState == MenuState.Ribbon && _ribbon.resolvedStyle.display == DisplayStyle.Flex) return;
2026-04-28 00:07:42 +07:00
_currentState = MenuState.Ribbon;
2026-04-28 10:44:22 +07:00
_lastInteractionTime = Time.time;
2026-04-26 05:20:47 +07:00
2026-04-28 00:07:42 +07:00
_ribbon.style.display = DisplayStyle.Flex;
2026-04-28 10:11:28 +07:00
Tween.Custom(0f, 1f, duration: 0.3f, onValueChange: val => _ribbon.style.opacity = val);
2026-04-28 10:44:22 +07:00
_logoSpace.RegisterCallback<GeometryChangedEvent>(OnLogoSpaceReady);
}
2026-04-28 10:11:28 +07:00
2026-04-28 10:44:22 +07:00
private void OnLogoSpaceReady(GeometryChangedEvent evt)
{
_logoSpace.UnregisterCallback<GeometryChangedEvent>(OnLogoSpaceReady);
2026-04-28 10:11:28 +07:00
Rect targetBounds = _logoSpace.worldBound;
2026-04-28 10:44:22 +07:00
if (targetBounds.width <= 0) return;
2026-04-29 01:04:28 +07:00
// Center logo in LogoSpace (within the centered Ribbon)
float targetX = targetBounds.x + (targetBounds.width / 2f) - 50f;
float targetY = targetBounds.y + (targetBounds.height / 2f) - 50f;
Tween.Custom(_logo.resolvedStyle.left, targetX, duration: 0.5f,
onValueChange: val => _logo.style.left = val,
ease: Ease.OutQuad);
2026-04-28 10:11:28 +07:00
2026-04-29 01:04:28 +07:00
Tween.Custom(_logo.resolvedStyle.top, targetY, duration: 0.5f,
onValueChange: val => _logo.style.top = val,
ease: Ease.OutQuad);
2026-04-28 10:11:28 +07:00
2026-04-29 01:04:28 +07:00
Tween.Custom(_logo.resolvedStyle.width, 100f, duration: 0.5f,
onValueChange: val => _logo.style.width = val,
ease: Ease.OutQuad);
2026-04-28 10:11:28 +07:00
2026-04-29 01:04:28 +07:00
Tween.Custom(_logo.resolvedStyle.height, 100f, duration: 0.5f,
onValueChange: val => _logo.style.height = val,
ease: Ease.OutQuad);
2026-04-28 10:25:34 +07:00
_lastInteractionTime = Time.time;
2026-04-27 13:27:40 +07:00
}
2026-04-28 00:07:42 +07:00
private void TransitionToIdle()
2026-04-26 05:20:47 +07:00
{
2026-04-28 10:25:34 +07:00
if (_currentState == MenuState.Idle) return;
2026-04-28 00:07:42 +07:00
_currentState = MenuState.Idle;
2026-04-28 10:11:28 +07:00
float targetX = (Screen.width / 2f) - 100;
float targetY = (Screen.height / 2f) - 100;
2026-04-29 01:04:28 +07:00
Tween.Custom(_logo.resolvedStyle.left, targetX, duration: 0.5f, onValueChange: val => _logo.style.left = val, ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.top, targetY, duration: 0.5f, onValueChange: val => _logo.style.top = val, ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.width, 200f, duration: 0.5f, onValueChange: val => _logo.style.width = val, ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.height, 200f, duration: 0.5f, onValueChange: val => _logo.style.height = val, ease: Ease.OutQuad);
2026-04-28 00:07:42 +07:00
Tween.Custom(1f, 0f, duration: 0.5f, onValueChange: val => _ribbon.style.opacity = val)
.OnComplete(() => _ribbon.style.display = DisplayStyle.None);
2026-04-26 05:20:47 +07:00
}
2026-04-28 00:07:42 +07:00
public void Update()
2026-04-26 04:39:59 +07:00
{
2026-04-28 10:44:22 +07:00
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0 || Input.anyKey)
{
_lastInteractionTime = Time.time;
}
2026-04-28 10:11:28 +07:00
if (_currentState == MenuState.Ribbon && Time.time - _lastInteractionTime > IDLE_TIMEOUT)
2026-04-28 00:07:42 +07:00
{
2026-04-28 10:11:28 +07:00
TransitionToIdle();
2026-04-28 00:07:42 +07:00
}
2026-04-26 04:39:59 +07:00
}
2026-04-26 05:20:47 +07:00
2026-04-28 10:11:28 +07:00
private void StartPulse()
2026-04-26 05:20:47 +07:00
{
2026-04-29 01:04:28 +07:00
if (_pulseTween.isAlive) _pulseTween.Stop();
_pulseTween = Tween.Custom(Vector3.one, Vector3.one * 1.1f, duration: 0.8f,
onValueChange: val => _logo.style.scale = new StyleScale(new Scale(val)),
cycles: -1,
cycleMode: CycleMode.Yoyo,
ease: Ease.InOutSine);
2026-04-26 05:20:47 +07:00
}
2026-04-25 18:20:16 +07:00
}
}