Files
aibis-dream/Assets/Scripts/UI/Terminal/TerminalPanel.cs
T

339 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
namespace AibisDream.UI
{
public enum TerminalPage
{
None,
Start,
Setting,
Chapter,
}
enum TerminalBootPhase
{
None,
PressAnyKey,
PlayingIntro,
PostIntroPause,
}
/// <summary>
/// 主菜单终端 Panel 壳:管理 Start / Chapter / Setting 三个 Page。
/// 冷启动时先走 Intro TimelinePress Any Key → 播放 → 停顿 → Start);同 session 内回主菜单跳过 Intro。
/// </summary>
public class TerminalPanel : MonoBehaviour, IUIPanel, ITerminalPanelHost
{
[SerializeField] private TerminalHeaderView header;
[SerializeField] private TerminalStartPanel startPage;
[SerializeField] private TerminalSettingPanel settingPage;
[SerializeField] private TerminalChapterPanel chapterPage;
[SerializeField] private PlayableDirector introDirector;
[SerializeField] private float postIntroPause = 0.5f;
[SerializeField] private GameObject menuFrame;
private readonly Stack<TerminalPage> _backStack = new();
private TerminalPage _currentPage = TerminalPage.None;
private bool _introCompletedThisSession;
private TerminalBootPhase _bootPhase = TerminalBootPhase.None;
public bool IsOpen =>
gameObject.activeSelf &&
(_bootPhase != TerminalBootPhase.None || _currentPage != TerminalPage.None);
public bool IsCloseable => false;
public TerminalPage CurrentPage => _currentPage;
public bool IsInGameContext => false;
public void Initialize()
{
startPage?.SetOwner(this);
settingPage?.SetOwner(this);
chapterPage?.SetOwner(this);
if (!HasRequiredPages())
{
Debug.LogError("[TerminalPanel] Missing required pages.");
}
Close();
}
public bool HasRequiredPages()
{
return startPage != null && settingPage != null && chapterPage != null;
}
public void Show()
{
if (_introCompletedThisSession)
{
TerminalUIAudio.NotifyMainMenuPhase(TerminalMainMenuPhase.Interactive);
Open(TerminalPage.Start);
return;
}
if (introDirector == null)
{
Debug.LogError("[TerminalPanel] introDirector is not assigned. Opening Start directly.");
_introCompletedThisSession = true;
TerminalUIAudio.NotifyMainMenuPhase(TerminalMainMenuPhase.Interactive);
Open(TerminalPage.Start);
return;
}
BeginBootSequence();
}
public void Hide()
{
Close();
}
private void Update()
{
if (_bootPhase != TerminalBootPhase.PressAnyKey)
{
return;
}
if (!TryGetBootInput())
{
return;
}
TerminalUIAudio.NotifyMainMenuPhase(TerminalMainMenuPhase.Interactive);
StartCoroutine(PlayIntroAndRevealStart());
}
private static bool TryGetBootInput()
{
if (Input.GetMouseButtonDown(0))
{
return true;
}
return Input.anyKeyDown;
}
private void BeginBootSequence()
{
gameObject.SetActive(true);
_backStack.Clear();
_currentPage = TerminalPage.None;
HideAllPages();
_bootPhase = TerminalBootPhase.PressAnyKey;
TerminalUIAudio.NotifyMainMenuPhase(TerminalMainMenuPhase.None);
}
private IEnumerator PlayIntroAndRevealStart()
{
_bootPhase = TerminalBootPhase.PlayingIntro;
introDirector.Play();
TerminalUIAudio.NotifyMainMenuPhase(TerminalMainMenuPhase.Boot);
while (introDirector.state == PlayState.Playing)
{
yield return null;
}
_bootPhase = TerminalBootPhase.PostIntroPause;
if (postIntroPause > 0f)
{
yield return new WaitForSecondsRealtime(postIntroPause);
}
_introCompletedThisSession = true;
_bootPhase = TerminalBootPhase.None;
menuFrame.SetActive(true);
Open(TerminalPage.Start);
}
public void Open(TerminalPage page)
{
if (!HasRequiredPages() || page == TerminalPage.None)
{
return;
}
if (!IsOpen)
{
_backStack.Clear();
}
gameObject.SetActive(true);
SwitchTo(page, pushCurrent: false);
}
public void SwitchTo(TerminalPage page, bool pushCurrent = true)
{
if (page == TerminalPage.None || page == _currentPage)
{
return;
}
if (pushCurrent && _currentPage != TerminalPage.None)
{
_backStack.Push(_currentPage);
}
var previous = _currentPage;
_currentPage = page;
if (previous == TerminalPage.None)
{
ShowPage(_currentPage);
return;
}
HidePage(previous, () => ShowPage(_currentPage));
}
public void Back()
{
if (_backStack.Count > 0)
{
var previous = _backStack.Pop();
var current = _currentPage;
_currentPage = previous;
HidePage(current, () => ShowPage(_currentPage));
return;
}
if (_currentPage != TerminalPage.Start)
{
SwitchTo(TerminalPage.Start, pushCurrent: false);
}
}
public bool HandleEscape()
{
if (!gameObject.activeSelf)
{
return false;
}
if (_bootPhase != TerminalBootPhase.None)
{
return true;
}
if (_currentPage == TerminalPage.None)
{
return false;
}
if (_currentPage == TerminalPage.Start)
{
return true;
}
Back();
return true;
}
public void CloseThen(Action action)
{
Close();
action?.Invoke();
}
public void Close()
{
if (introDirector != null)
{
introDirector.Stop();
}
HideAllPages();
_backStack.Clear();
_currentPage = TerminalPage.None;
_bootPhase = TerminalBootPhase.None;
gameObject.SetActive(false);
}
public void CloseToMainMenu()
{
Close();
GameManager.Instance.TryReturnToMainMenu();
}
public void SetHeader(string title, string status = "")
{
header?.SetText(title, status);
}
private void ShowPage(TerminalPage page)
{
switch (page)
{
case TerminalPage.Start:
startPage?.Show();
break;
case TerminalPage.Setting:
settingPage?.Show();
break;
case TerminalPage.Chapter:
chapterPage?.Show();
break;
}
}
private void HidePage(TerminalPage page, Action onComplete = null)
{
switch (page)
{
case TerminalPage.Start:
HidePage(startPage, onComplete);
break;
case TerminalPage.Setting:
HidePage(settingPage, onComplete);
break;
case TerminalPage.Chapter:
HidePage(chapterPage, onComplete);
break;
default:
onComplete?.Invoke();
break;
}
}
private static void HidePage(MonoBehaviour page, Action onComplete)
{
if (page == null)
{
onComplete?.Invoke();
return;
}
switch (page)
{
case TerminalStartPanel startPanel:
startPanel.Hide(onComplete);
break;
case TerminalSettingPanel settingPanel:
settingPanel.Hide(onComplete);
break;
case TerminalChapterPanel chapterPanel:
chapterPanel.Hide(onComplete);
break;
default:
page.gameObject.SetActive(false);
onComplete?.Invoke();
break;
}
}
private void HideAllPages()
{
startPage?.Hide();
settingPage?.Hide();
chapterPage?.Hide();
}
}
}