feat(ui): 重构终端面板,拆分主菜单与局内终端
This commit is contained in:
@@ -3,7 +3,6 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.UI;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.SaveSystem
|
||||
@@ -277,6 +276,7 @@ namespace AibisDream.SaveSystem
|
||||
if (ui != null)
|
||||
{
|
||||
ui.HideTerminal();
|
||||
ui.GetPanel<InGameTerminalPanel>()?.Close();
|
||||
ui.ShowPanel<MainPanel>();
|
||||
ui.HidePanel<SavesPanel>();
|
||||
ui.HidePanel<EndPanel>();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Kit;
|
||||
using AibisDream.UI;
|
||||
using AibisDream.UI.Terminal;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -36,12 +35,14 @@ namespace AibisDream
|
||||
return;
|
||||
}
|
||||
|
||||
UIManager.Instance.GetPanel<TerminalPanel>()?.AppendDialogLine(line);
|
||||
var panel = UIManager.Instance.GetPanel<InGameTerminalPanel>();
|
||||
panel?.AppendDialogLine(line);
|
||||
}
|
||||
|
||||
private void CleanDialogHistory()
|
||||
{
|
||||
UIManager.Instance.GetPanel<TerminalPanel>()?.ClearDialog();
|
||||
var panel = UIManager.Instance.GetPanel<InGameTerminalPanel>();
|
||||
panel?.ClearDialog();
|
||||
}
|
||||
|
||||
public void CloseCanvas()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public interface ITerminalPanelHost
|
||||
{
|
||||
void SetHeader(string title, string status = "");
|
||||
void Back();
|
||||
void Close();
|
||||
void CloseToMainMenu();
|
||||
bool IsInGameContext { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7c6d5e4f3a2918071625344a5b6c7d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public enum InGameTerminalPage
|
||||
{
|
||||
None,
|
||||
Setting,
|
||||
Record,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 局内终端 Panel 壳:管理 Setting / Record 两个 Page。
|
||||
/// Setting / Record 需在场景中分别挂独立的 Prefab 实例,并在 Inspector 中绑定。
|
||||
/// </summary>
|
||||
public class InGameTerminalPanel : MonoBehaviour, IUIPanel, ITerminalPanelHost
|
||||
{
|
||||
[SerializeField] private TerminalHeaderView header;
|
||||
[SerializeField] private TerminalSettingPanel settingPage;
|
||||
[SerializeField] private TerminalRecordPanel recordPage;
|
||||
|
||||
private readonly Stack<InGameTerminalPage> _backStack = new();
|
||||
private InGameTerminalPage _currentPage = InGameTerminalPage.None;
|
||||
private bool _pausedByPanel;
|
||||
|
||||
public bool IsOpen => gameObject.activeSelf && _currentPage != InGameTerminalPage.None;
|
||||
public bool IsCloseable => true;
|
||||
public InGameTerminalPage CurrentPage => _currentPage;
|
||||
public bool IsInGameContext => true;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var root = transform;
|
||||
settingPage ??= root.GetComponentInChildren<TerminalSettingPanel>(true);
|
||||
recordPage ??= root.GetComponentInChildren<TerminalRecordPanel>(true);
|
||||
|
||||
settingPage?.SetOwner(this);
|
||||
recordPage?.SetOwner(this);
|
||||
Close();
|
||||
}
|
||||
|
||||
public bool HasRequiredPages()
|
||||
{
|
||||
return settingPage != null && recordPage != null;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
Open(InGameTerminalPage.Setting);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Open(InGameTerminalPage page)
|
||||
{
|
||||
if (!HasRequiredPages() || page == InGameTerminalPage.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsOpen)
|
||||
{
|
||||
_backStack.Clear();
|
||||
}
|
||||
|
||||
gameObject.SetActive(true);
|
||||
PauseIfNeeded();
|
||||
SwitchTo(page, pushCurrent: false);
|
||||
}
|
||||
|
||||
public void SwitchTo(InGameTerminalPage page, bool pushCurrent = true)
|
||||
{
|
||||
if (page == InGameTerminalPage.None || page == _currentPage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pushCurrent && _currentPage != InGameTerminalPage.None)
|
||||
{
|
||||
_backStack.Push(_currentPage);
|
||||
}
|
||||
|
||||
var previous = _currentPage;
|
||||
_currentPage = page;
|
||||
|
||||
if (previous == InGameTerminalPage.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;
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
public bool HandleEscape()
|
||||
{
|
||||
if (!IsOpen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Back();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
HideAllPages();
|
||||
_backStack.Clear();
|
||||
_currentPage = InGameTerminalPage.None;
|
||||
ContinueIfPaused();
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void CloseToMainMenu()
|
||||
{
|
||||
Close();
|
||||
GameManager.Instance.QuitGame();
|
||||
}
|
||||
|
||||
public void SetHeader(string title, string status = "")
|
||||
{
|
||||
header?.SetText(title, status);
|
||||
}
|
||||
|
||||
public void AppendDialogLine(LineInfo lineInfo)
|
||||
{
|
||||
recordPage?.AppendDialogLine(lineInfo);
|
||||
}
|
||||
|
||||
public void ClearDialog()
|
||||
{
|
||||
recordPage?.ClearDialog();
|
||||
}
|
||||
|
||||
private void PauseIfNeeded()
|
||||
{
|
||||
if (GameManager.Instance == null || !GameManager.Instance.state.isInGame || _pausedByPanel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.PauseGame();
|
||||
_pausedByPanel = true;
|
||||
}
|
||||
|
||||
private void ContinueIfPaused()
|
||||
{
|
||||
if (!_pausedByPanel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.ContinueGame();
|
||||
_pausedByPanel = false;
|
||||
}
|
||||
|
||||
private void ShowPage(InGameTerminalPage page)
|
||||
{
|
||||
switch (page)
|
||||
{
|
||||
case InGameTerminalPage.Setting:
|
||||
settingPage?.Show();
|
||||
break;
|
||||
case InGameTerminalPage.Record:
|
||||
recordPage?.Show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HidePage(InGameTerminalPage page, Action onComplete = null)
|
||||
{
|
||||
switch (page)
|
||||
{
|
||||
case InGameTerminalPage.Setting:
|
||||
settingPage?.Hide(onComplete);
|
||||
break;
|
||||
case InGameTerminalPage.Record:
|
||||
recordPage?.Hide(onComplete);
|
||||
break;
|
||||
default:
|
||||
onComplete?.Invoke();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HideAllPages()
|
||||
{
|
||||
settingPage?.Hide();
|
||||
recordPage?.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8f4a2b1c3d54e6f9a0b1c2d3e4f5a6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using AibisDream;
|
||||
using AibisDream.Utility;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Components;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
[RequireComponent(typeof(BaseButton))]
|
||||
public class TerminalButton : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private BaseButton button;
|
||||
[SerializeField] private Image buttonImage;
|
||||
[SerializeField] private Image backgroundImage;
|
||||
[SerializeField] private TMP_Text labelText;
|
||||
[SerializeField] private LocalizeStringEvent labelLocalize;
|
||||
|
||||
[Header("文字")]
|
||||
[SerializeField] private string defaultLabel = string.Empty;
|
||||
|
||||
[Header("前景色彩(文字 + 按钮图)")]
|
||||
[SerializeField] private Color normalForegroundColor = Color.white;
|
||||
[SerializeField] private Color hoverForegroundColor = new Color(0.02f, 0.02f, 0.04f);
|
||||
|
||||
[Header("底图色彩")]
|
||||
[SerializeField] private Color normalBackgroundColor = new Color(1f, 1f, 1f, 0f);
|
||||
[SerializeField] private Color hoverBackgroundColor = Color.white;
|
||||
|
||||
[Header("禁用")]
|
||||
[SerializeField] private Color disabledForegroundColor = new Color(0.78431374f, 0.78431374f, 0.78431374f, 0.5f);
|
||||
[SerializeField] private Color disabledBackgroundColor = new Color(1f, 1f, 1f, 0.3f);
|
||||
|
||||
|
||||
|
||||
public BaseButton Button => button != null ? button : (button = GetComponent<BaseButton>());
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
button = GetComponent<BaseButton>();
|
||||
if (buttonImage == null)
|
||||
{
|
||||
buttonImage = GetComponent<Image>();
|
||||
}
|
||||
|
||||
if (labelLocalize == null && labelText != null)
|
||||
{
|
||||
labelLocalize = labelText.GetComponent<LocalizeStringEvent>();
|
||||
}
|
||||
|
||||
button.onStateTransition.AddListener(OnStateTransition);
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultLabel))
|
||||
{
|
||||
SetLabel(defaultLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
OnStateTransition(button.CurSelectionState, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.onStateTransition.RemoveListener(OnStateTransition);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLabel(string value)
|
||||
{
|
||||
if (labelLocalize != null && IsLocalizationKey(value))
|
||||
{
|
||||
labelLocalize.enabled = true;
|
||||
labelLocalize.SetTable(ConstRef.UITextTable);
|
||||
labelLocalize.SetEntry(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (labelLocalize != null)
|
||||
{
|
||||
labelLocalize.enabled = false;
|
||||
}
|
||||
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStateTransition(SelectionType state, bool instant)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case SelectionType.Disabled:
|
||||
ApplyForegroundColor(disabledForegroundColor);
|
||||
ApplyBackgroundColor(disabledBackgroundColor);
|
||||
break;
|
||||
case SelectionType.Highlighted:
|
||||
case SelectionType.Pressed:
|
||||
case SelectionType.Selected:
|
||||
ApplyForegroundColor(hoverForegroundColor);
|
||||
ApplyBackgroundColor(hoverBackgroundColor);
|
||||
break;
|
||||
default:
|
||||
ApplyForegroundColor(normalForegroundColor);
|
||||
ApplyBackgroundColor(normalBackgroundColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyForegroundColor(Color color)
|
||||
{
|
||||
if (buttonImage != null)
|
||||
{
|
||||
buttonImage.color = color;
|
||||
}
|
||||
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyBackgroundColor(Color color)
|
||||
{
|
||||
if (backgroundImage != null)
|
||||
{
|
||||
backgroundImage.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLocalizationKey(string value)
|
||||
{
|
||||
return !string.IsNullOrEmpty(value) && value.Contains("_", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: febed96817a804e47ace59be0d7c3995
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,7 +3,7 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
[RequireComponent(typeof(BaseButton))]
|
||||
public class TerminalChapterItemView : MonoBehaviour
|
||||
@@ -14,8 +14,8 @@ namespace AibisDream.UI.Terminal
|
||||
[SerializeField] private TMP_Text statusText;
|
||||
[SerializeField] private Image selectionFrame;
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private float selectedScale = 1.05f;
|
||||
[SerializeField] private float previewScale = 1f;
|
||||
[SerializeField] private float selectedScale = 1f;
|
||||
[SerializeField] private float previewScale = 0.45f;
|
||||
|
||||
private BaseButton _button;
|
||||
private ChapterVo _chapterVo;
|
||||
@@ -52,7 +52,9 @@ namespace AibisDream.UI.Terminal
|
||||
if (coverImage != null)
|
||||
{
|
||||
coverImage.sprite = chapterVo.pic;
|
||||
coverImage.enabled = chapterVo.pic != null;
|
||||
var hasCover = chapterVo.pic != null;
|
||||
coverImage.enabled = hasCover;
|
||||
coverImage.preserveAspect = true;
|
||||
}
|
||||
|
||||
if (titleText != null)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalChapterPanel : MonoBehaviour
|
||||
{
|
||||
@@ -47,31 +48,37 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_owner?.SetHeader("<选择章节>");
|
||||
LoadChapters();
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show(RefreshViews);
|
||||
panelAnimator.Show(prepare: PrepareContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareContent();
|
||||
gameObject.SetActive(true);
|
||||
RefreshViews();
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
public void Hide(Action onComplete = null)
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide();
|
||||
panelAnimator.Hide(onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareContent()
|
||||
{
|
||||
_owner?.SetHeader("terminal_header_chapter", "REPAIR_STATION_07 - AUTH_VERIFIED");
|
||||
LoadChapters();
|
||||
RefreshViews();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_owner.Back();
|
||||
|
||||
@@ -1,24 +1,59 @@
|
||||
using System;
|
||||
using AibisDream.Utility;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Components;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalHeaderView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text titleText;
|
||||
[SerializeField] private LocalizeStringEvent titleLocalize;
|
||||
[SerializeField] private TMP_Text statusText;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (titleLocalize == null && titleText != null)
|
||||
{
|
||||
titleLocalize = titleText.GetComponent<LocalizeStringEvent>();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetText(string title, string status = "")
|
||||
{
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = title;
|
||||
}
|
||||
SetTitle(title);
|
||||
|
||||
if (statusText != null)
|
||||
{
|
||||
statusText.text = status;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTitle(string title)
|
||||
{
|
||||
if (titleLocalize != null && IsLocalizationKey(title))
|
||||
{
|
||||
titleLocalize.enabled = true;
|
||||
titleLocalize.SetTable(ConstRef.UITextTable);
|
||||
titleLocalize.SetEntry(title);
|
||||
return;
|
||||
}
|
||||
|
||||
if (titleLocalize != null)
|
||||
{
|
||||
titleLocalize.enabled = false;
|
||||
}
|
||||
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = title;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLocalizationKey(string value)
|
||||
{
|
||||
return !string.IsNullOrEmpty(value) && value.Contains("_", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalLoadingPanel : MonoBehaviour, IUIPanel
|
||||
{
|
||||
@@ -18,6 +19,32 @@ namespace AibisDream.UI.Terminal
|
||||
public bool IsCloseable => false;
|
||||
|
||||
public void Show()
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show(prepare: PrepareContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareContent();
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide(Action onComplete = null)
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide(onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareContent()
|
||||
{
|
||||
SetText(companyText, "SATISFYING INC");
|
||||
SetText(deviceText, "Device Model: Dell P5999 DX130\nDevice Serial Number: SN46456546DAS");
|
||||
@@ -29,27 +56,6 @@ namespace AibisDream.UI.Terminal
|
||||
{
|
||||
avatarImage.gameObject.SetActive(avatarImage.sprite != null);
|
||||
}
|
||||
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProgress(float progress)
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
using System;
|
||||
using AibisDream.Utility;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Components;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
[RequireComponent(typeof(BaseButton))]
|
||||
public class TerminalMenuItemView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text labelText;
|
||||
[SerializeField] private LocalizeStringEvent labelLocalize;
|
||||
[SerializeField] private TMP_Text statusText;
|
||||
[SerializeField] private TMP_Text detailText;
|
||||
[SerializeField] private TMP_Text cursor;
|
||||
[SerializeField] private Image selectionBar;
|
||||
[SerializeField] private string defaultLabelKey = string.Empty;
|
||||
[SerializeField] private Color normalTextColor = Color.white;
|
||||
[SerializeField] private Color selectedTextColor = new Color(0.02f, 0.02f, 0.04f);
|
||||
[SerializeField] private Color dangerTextColor = new Color(1f, 0.18f, 0.2f);
|
||||
@@ -35,9 +39,19 @@ namespace AibisDream.UI.Terminal
|
||||
_canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
if (labelLocalize == null && labelText != null)
|
||||
{
|
||||
labelLocalize = labelText.GetComponent<LocalizeStringEvent>();
|
||||
}
|
||||
|
||||
_button.onClick.AddListener(HandleClick);
|
||||
_button.onStateTransition.AddListener(OnButtonStateTransition);
|
||||
SetSelected(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(defaultLabelKey))
|
||||
{
|
||||
SetLabel(defaultLabelKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@@ -49,13 +63,9 @@ namespace AibisDream.UI.Terminal
|
||||
}
|
||||
}
|
||||
|
||||
public void SetContent(string label, string status = "", string detail = "", bool isDanger = false)
|
||||
public void SetContent(string label, string status = "", string detail = "")
|
||||
{
|
||||
_isDanger = isDanger;
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.text = label;
|
||||
}
|
||||
SetLabel(label);
|
||||
|
||||
if (statusText != null)
|
||||
{
|
||||
@@ -70,6 +80,27 @@ namespace AibisDream.UI.Terminal
|
||||
RefreshVisual();
|
||||
}
|
||||
|
||||
public void SetLabel(string value)
|
||||
{
|
||||
if (labelLocalize != null && IsLocalizationKey(value))
|
||||
{
|
||||
labelLocalize.enabled = true;
|
||||
labelLocalize.SetTable(ConstRef.UITextTable);
|
||||
labelLocalize.SetEntry(value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (labelLocalize != null)
|
||||
{
|
||||
labelLocalize.enabled = false;
|
||||
}
|
||||
|
||||
if (labelText != null)
|
||||
{
|
||||
labelText.text = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInteractable(bool interactable)
|
||||
{
|
||||
if (_button != null)
|
||||
@@ -135,5 +166,10 @@ namespace AibisDream.UI.Terminal
|
||||
text.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLocalizationKey(string value)
|
||||
{
|
||||
return !string.IsNullOrEmpty(value) && value.Contains("_", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalOptionItemView : MonoBehaviour
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public enum TerminalPage
|
||||
{
|
||||
@@ -10,56 +11,47 @@ namespace AibisDream.UI.Terminal
|
||||
Start,
|
||||
Setting,
|
||||
Chapter,
|
||||
Record
|
||||
}
|
||||
|
||||
public enum TerminalOpenSource
|
||||
{
|
||||
None,
|
||||
MainMenu,
|
||||
InGame
|
||||
}
|
||||
|
||||
public class TerminalPanel : MonoBehaviour, IUIPanel
|
||||
/// <summary>
|
||||
/// 主菜单终端 Panel 壳:管理 Start / Chapter / Setting 三个 Page。
|
||||
/// </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 TerminalRecordPanel recordPage;
|
||||
|
||||
private readonly Stack<TerminalPage> _backStack = new();
|
||||
private TerminalPage _currentPage = TerminalPage.None;
|
||||
private TerminalOpenSource _source = TerminalOpenSource.None;
|
||||
private bool _pausedByTerminal;
|
||||
|
||||
public bool IsOpen => gameObject.activeSelf && _currentPage != TerminalPage.None;
|
||||
public bool IsCloseable => _source == TerminalOpenSource.InGame;
|
||||
public bool IsCloseable => false;
|
||||
public TerminalPage CurrentPage => _currentPage;
|
||||
public TerminalOpenSource Source => _source;
|
||||
public bool IsInGameContext => false;
|
||||
|
||||
public void Initialize(RectTransform searchRoot)
|
||||
public void Initialize()
|
||||
{
|
||||
startPage ??= searchRoot.GetComponentInChildren<TerminalStartPanel>(true);
|
||||
settingPage ??= searchRoot.GetComponentInChildren<TerminalSettingPanel>(true);
|
||||
chapterPage ??= searchRoot.GetComponentInChildren<TerminalChapterPanel>(true);
|
||||
recordPage ??= searchRoot.GetComponentInChildren<TerminalRecordPanel>(true);
|
||||
var root = transform;
|
||||
startPage ??= root.GetComponentInChildren<TerminalStartPanel>(true);
|
||||
settingPage ??= root.GetComponentInChildren<TerminalSettingPanel>(true);
|
||||
chapterPage ??= root.GetComponentInChildren<TerminalChapterPanel>(true);
|
||||
|
||||
startPage?.SetOwner(this);
|
||||
settingPage?.SetOwner(this);
|
||||
chapterPage?.SetOwner(this);
|
||||
recordPage?.SetOwner(this);
|
||||
Close();
|
||||
}
|
||||
|
||||
public bool HasRequiredPages()
|
||||
{
|
||||
return startPage != null && settingPage != null && chapterPage != null && recordPage != null;
|
||||
return startPage != null && settingPage != null && chapterPage != null;
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
Open(TerminalPage.Start, TerminalOpenSource.MainMenu);
|
||||
Open(TerminalPage.Start);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
@@ -67,21 +59,19 @@ namespace AibisDream.UI.Terminal
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Open(TerminalPage page, TerminalOpenSource source)
|
||||
public void Open(TerminalPage page)
|
||||
{
|
||||
if (!HasRequiredPages())
|
||||
if (!HasRequiredPages() || page == TerminalPage.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsOpen || _source != source)
|
||||
if (!IsOpen)
|
||||
{
|
||||
_backStack.Clear();
|
||||
}
|
||||
|
||||
gameObject.SetActive(true);
|
||||
_source = source;
|
||||
PauseIfNeeded(page, source);
|
||||
SwitchTo(page, pushCurrent: false);
|
||||
}
|
||||
|
||||
@@ -97,25 +87,26 @@ namespace AibisDream.UI.Terminal
|
||||
_backStack.Push(_currentPage);
|
||||
}
|
||||
|
||||
HidePage(_currentPage);
|
||||
var previous = _currentPage;
|
||||
_currentPage = page;
|
||||
ShowPage(_currentPage);
|
||||
|
||||
if (previous == TerminalPage.None)
|
||||
{
|
||||
ShowPage(_currentPage);
|
||||
return;
|
||||
}
|
||||
|
||||
HidePage(previous, () => ShowPage(_currentPage));
|
||||
}
|
||||
|
||||
public void Back()
|
||||
{
|
||||
if (_source == TerminalOpenSource.InGame)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_backStack.Count > 0)
|
||||
{
|
||||
var previous = _backStack.Pop();
|
||||
HidePage(_currentPage);
|
||||
var current = _currentPage;
|
||||
_currentPage = previous;
|
||||
ShowPage(_currentPage);
|
||||
HidePage(current, () => ShowPage(_currentPage));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,8 +143,6 @@ namespace AibisDream.UI.Terminal
|
||||
HideAllPages();
|
||||
_backStack.Clear();
|
||||
_currentPage = TerminalPage.None;
|
||||
_source = TerminalOpenSource.None;
|
||||
ContinueIfPaused();
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
@@ -163,46 +152,11 @@ namespace AibisDream.UI.Terminal
|
||||
GameManager.Instance.QuitGame();
|
||||
}
|
||||
|
||||
public void AppendDialogLine(LineInfo lineInfo)
|
||||
{
|
||||
recordPage?.AppendDialogLine(lineInfo);
|
||||
}
|
||||
|
||||
public void ClearDialog()
|
||||
{
|
||||
recordPage?.ClearDialog();
|
||||
}
|
||||
|
||||
public void SetHeader(string title, string status = "")
|
||||
{
|
||||
header?.SetText(title, status);
|
||||
}
|
||||
|
||||
private void PauseIfNeeded(TerminalPage page, TerminalOpenSource source)
|
||||
{
|
||||
if (source != TerminalOpenSource.InGame || page is not (TerminalPage.Setting or TerminalPage.Record))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_pausedByTerminal)
|
||||
{
|
||||
GameManager.Instance.PauseGame();
|
||||
_pausedByTerminal = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ContinueIfPaused()
|
||||
{
|
||||
if (!_pausedByTerminal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.ContinueGame();
|
||||
_pausedByTerminal = false;
|
||||
}
|
||||
|
||||
private void ShowPage(TerminalPage page)
|
||||
{
|
||||
switch (page)
|
||||
@@ -216,27 +170,50 @@ namespace AibisDream.UI.Terminal
|
||||
case TerminalPage.Chapter:
|
||||
chapterPage?.Show();
|
||||
break;
|
||||
case TerminalPage.Record:
|
||||
recordPage?.Show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HidePage(TerminalPage page)
|
||||
private void HidePage(TerminalPage page, Action onComplete = null)
|
||||
{
|
||||
switch (page)
|
||||
{
|
||||
case TerminalPage.Start:
|
||||
startPage?.Hide();
|
||||
HidePage(startPage, onComplete);
|
||||
break;
|
||||
case TerminalPage.Setting:
|
||||
settingPage?.Hide();
|
||||
HidePage(settingPage, onComplete);
|
||||
break;
|
||||
case TerminalPage.Chapter:
|
||||
chapterPage?.Hide();
|
||||
HidePage(chapterPage, onComplete);
|
||||
break;
|
||||
case TerminalPage.Record:
|
||||
recordPage?.Hide();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -246,7 +223,6 @@ namespace AibisDream.UI.Terminal
|
||||
startPage?.Hide();
|
||||
settingPage?.Hide();
|
||||
chapterPage?.Hide();
|
||||
recordPage?.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
using System;
|
||||
using System;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalPanelAnimator : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private CanvasGroup canvasGroup;
|
||||
[SerializeField] private RectTransform sweep;
|
||||
[SerializeField] private float fadeDuration = 0.18f;
|
||||
[SerializeField] private float sweepDuration = 0.24f;
|
||||
|
||||
[Header("终端风格")]
|
||||
[SerializeField, Range(0f, 1f)] private float visibleAlpha = 0.88f;
|
||||
[SerializeField] private float fadeDuration = 0.06f;
|
||||
[SerializeField] private Ease showEase = Ease.Linear;
|
||||
[SerializeField] private Ease hideEase = Ease.Linear;
|
||||
[SerializeField] private float sweepDuration = 0.08f;
|
||||
|
||||
private Tween _activeTween;
|
||||
|
||||
@@ -21,10 +26,23 @@ namespace AibisDream.UI.Terminal
|
||||
}
|
||||
}
|
||||
|
||||
public void Show(Action onComplete = null)
|
||||
/// <param name="onComplete">淡入完成回调。</param>
|
||||
/// <param name="prepare">在 SetActive 之前执行的内容准备(赋值、布局等)。</param>
|
||||
public void Show(Action onComplete = null, Action prepare = null)
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
_activeTween?.Kill();
|
||||
prepare?.Invoke();
|
||||
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
PrepareSweep();
|
||||
gameObject.SetActive(true);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
@@ -32,16 +50,11 @@ namespace AibisDream.UI.Terminal
|
||||
return;
|
||||
}
|
||||
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
PrepareSweep();
|
||||
|
||||
var sequence = DOTween.Sequence().SetUpdate(true);
|
||||
sequence.Join(canvasGroup.DOFade(1f, fadeDuration));
|
||||
sequence.Join(canvasGroup.DOFade(visibleAlpha, fadeDuration).SetEase(showEase));
|
||||
if (sweep != null)
|
||||
{
|
||||
sequence.Join(sweep.DOAnchorPosX(0f, sweepDuration).SetEase(Ease.OutQuad));
|
||||
sequence.Join(sweep.DOAnchorPosX(0f, sweepDuration).SetEase(Ease.Linear));
|
||||
}
|
||||
|
||||
sequence.OnComplete(() =>
|
||||
@@ -69,6 +82,7 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
_activeTween = canvasGroup
|
||||
.DOFade(0f, fadeDuration)
|
||||
.SetEase(hideEase)
|
||||
.SetUpdate(true)
|
||||
.OnComplete(() =>
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalRecordItemView : MonoBehaviour
|
||||
{
|
||||
@@ -13,11 +13,13 @@ namespace AibisDream.UI.Terminal
|
||||
if (actorNameText != null)
|
||||
{
|
||||
actorNameText.text = lineInfo.character.GetActorName();
|
||||
actorNameText.ForceMeshUpdate();
|
||||
}
|
||||
|
||||
if (lineText != null)
|
||||
{
|
||||
lineText.text = lineInfo.GetRecordLine();
|
||||
lineText.ForceMeshUpdate();
|
||||
}
|
||||
|
||||
gameObject.SetActive(true);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Utility;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 终端 Record Page(遗留类名 Panel)。挂在局内 InGameTerminalPanel 壳下。
|
||||
/// </summary>
|
||||
public class TerminalRecordPanel : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TerminalPanelAnimator panelAnimator;
|
||||
@@ -16,11 +20,11 @@ namespace AibisDream.UI.Terminal
|
||||
[SerializeField] private TMP_Text emptyText;
|
||||
|
||||
private readonly List<LineInfo> _recordDataList = new List<LineInfo>();
|
||||
private InGameTerminalPanel _owner;
|
||||
|
||||
public bool IsOpen => gameObject.activeSelf;
|
||||
private TerminalPanel _owner;
|
||||
|
||||
public void SetOwner(TerminalPanel owner)
|
||||
public void SetOwner(InGameTerminalPanel owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
@@ -28,6 +32,39 @@ namespace AibisDream.UI.Terminal
|
||||
private void Awake()
|
||||
{
|
||||
backButton?.onClick.AddListener(ReturnGame);
|
||||
EnsureScrollViewportMask();
|
||||
}
|
||||
|
||||
private void EnsureScrollViewportMask()
|
||||
{
|
||||
if (scrollRect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var legacyMask = scrollRect.GetComponent<Mask>();
|
||||
if (legacyMask != null)
|
||||
{
|
||||
legacyMask.enabled = false;
|
||||
}
|
||||
|
||||
if (scrollRect.TryGetComponent<Image>(out var scrollImage))
|
||||
{
|
||||
var color = scrollImage.color;
|
||||
color.a = 0f;
|
||||
scrollImage.color = color;
|
||||
scrollImage.raycastTarget = true;
|
||||
}
|
||||
|
||||
if (scrollRect.viewport == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (scrollRect.viewport.GetComponent<RectMask2D>() == null)
|
||||
{
|
||||
scrollRect.viewport.gameObject.AddComponent<RectMask2D>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@@ -37,30 +74,34 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_owner?.SetHeader("<诊疗记录>", "EMR 511/42 - Clinical Record");
|
||||
DrawRecords();
|
||||
_owner?.SetHeader("termnial_header_record", "REPAIR_STATION_07 - AUTH_VERIFIED");
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show();
|
||||
panelAnimator.Show(onComplete: () => StartCoroutine(DrawRecordsWhenReady()));
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
StartCoroutine(DrawRecordsWhenReady());
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
public void Hide(Action onComplete = null)
|
||||
{
|
||||
ClearRecordItems();
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide();
|
||||
panelAnimator.Hide(() =>
|
||||
{
|
||||
ClearRecordItems();
|
||||
onComplete?.Invoke();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearRecordItems();
|
||||
gameObject.SetActive(false);
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void AppendDialogLine(LineInfo lineInfo)
|
||||
@@ -73,10 +114,50 @@ namespace AibisDream.UI.Terminal
|
||||
_recordDataList.Clear();
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator DrawRecordsWhenReady()
|
||||
{
|
||||
yield return null;
|
||||
DrawRecords();
|
||||
}
|
||||
|
||||
private void ConfigureContentRect()
|
||||
{
|
||||
if (recordRoot is not RectTransform content)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
content.anchorMin = new Vector2(0f, 1f);
|
||||
content.anchorMax = new Vector2(1f, 1f);
|
||||
content.pivot = new Vector2(0.5f, 1f);
|
||||
content.anchoredPosition = Vector2.zero;
|
||||
content.sizeDelta = Vector2.zero;
|
||||
}
|
||||
|
||||
private static void ConfigureRecordItemRect(RectTransform itemRect)
|
||||
{
|
||||
itemRect.anchorMin = new Vector2(0f, 1f);
|
||||
itemRect.anchorMax = new Vector2(1f, 1f);
|
||||
itemRect.pivot = new Vector2(0.5f, 1f);
|
||||
itemRect.sizeDelta = Vector2.zero;
|
||||
}
|
||||
|
||||
private static void SyncUiLayer(GameObject target, int layer)
|
||||
{
|
||||
target.layer = layer;
|
||||
for (var i = 0; i < target.transform.childCount; i++)
|
||||
{
|
||||
SyncUiLayer(target.transform.GetChild(i).gameObject, layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRecords()
|
||||
{
|
||||
ClearRecordItems();
|
||||
ConfigureContentRect();
|
||||
|
||||
var hasRecords = _recordDataList.Count > 0;
|
||||
|
||||
if (emptyText != null)
|
||||
{
|
||||
emptyText.gameObject.SetActive(!hasRecords);
|
||||
@@ -85,12 +166,24 @@ namespace AibisDream.UI.Terminal
|
||||
foreach (var recordData in _recordDataList)
|
||||
{
|
||||
var item = Instantiate(recordItemPrefab, recordRoot);
|
||||
SyncUiLayer(item.gameObject, recordRoot.gameObject.layer);
|
||||
item.Init(recordData);
|
||||
|
||||
if (item.transform is RectTransform itemRect)
|
||||
{
|
||||
ConfigureRecordItemRect(itemRect);
|
||||
}
|
||||
}
|
||||
|
||||
if (recordRoot is RectTransform contentRect)
|
||||
{
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(contentRect);
|
||||
}
|
||||
|
||||
if (scrollRect != null)
|
||||
{
|
||||
scrollRect.verticalNormalizedPosition = 0f;
|
||||
Canvas.ForceUpdateCanvases();
|
||||
scrollRect.verticalNormalizedPosition = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +197,7 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
private void ReturnGame()
|
||||
{
|
||||
_owner.Back();
|
||||
_owner?.Back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System;
|
||||
using AibisDream;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 终端 Setting Page(遗留类名 Panel)。可挂在主菜单或局内 Panel 壳下。
|
||||
/// </summary>
|
||||
public class TerminalSettingPanel : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TerminalPanelAnimator panelAnimator;
|
||||
@@ -10,12 +14,15 @@ namespace AibisDream.UI.Terminal
|
||||
[SerializeField] private SelectItem textSpeedOption;
|
||||
[SerializeField] private SelectItem windowModeOption;
|
||||
[SerializeField] private SelectItem languageOption;
|
||||
[SerializeField] private Button continueButton;
|
||||
[SerializeField] private Button backToMainButton;
|
||||
[SerializeField] private Button quitButton;
|
||||
[SerializeField] private TerminalButton continueButton;
|
||||
[SerializeField] private TerminalButton backToMainButton;
|
||||
[SerializeField] private TerminalButton quitButton;
|
||||
|
||||
public bool IsOpen => gameObject.activeSelf;
|
||||
private TerminalPanel _owner;
|
||||
private ITerminalPanelHost _owner;
|
||||
private RectTransform _continueButtonRect;
|
||||
private Vector2 _continueButtonDefaultPosition;
|
||||
private bool _hasContinueButtonDefaultPosition;
|
||||
|
||||
private static readonly UIFormOption[] WindowModeOptions =
|
||||
{
|
||||
@@ -37,59 +44,85 @@ namespace AibisDream.UI.Terminal
|
||||
new UIFormOption { prop = "3.0", label = "setting_textSpeed_fast" },
|
||||
};
|
||||
|
||||
public void SetOwner(TerminalPanel owner)
|
||||
public void SetOwner(ITerminalPanelHost owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
continueButton?.onClick.AddListener(BackToGame);
|
||||
backToMainButton?.onClick.AddListener(BackToMain);
|
||||
quitButton?.onClick.AddListener(QuitApp);
|
||||
BindButton(continueButton, BackToGame);
|
||||
BindButton(backToMainButton, BackToMain);
|
||||
BindButton(quitButton, QuitApp);
|
||||
|
||||
if (continueButton != null)
|
||||
{
|
||||
_continueButtonRect = continueButton.transform as RectTransform;
|
||||
if (_continueButtonRect != null)
|
||||
{
|
||||
_continueButtonDefaultPosition = _continueButtonRect.anchoredPosition;
|
||||
_hasContinueButtonDefaultPosition = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
continueButton?.onClick.RemoveListener(BackToGame);
|
||||
backToMainButton?.onClick.RemoveListener(BackToMain);
|
||||
quitButton?.onClick.RemoveListener(QuitApp);
|
||||
UnbindButton(continueButton, BackToGame);
|
||||
UnbindButton(backToMainButton, BackToMain);
|
||||
UnbindButton(quitButton, QuitApp);
|
||||
}
|
||||
|
||||
private static void BindButton(TerminalButton terminalButton, UnityEngine.Events.UnityAction action)
|
||||
{
|
||||
terminalButton?.Button?.onClick.AddListener(action);
|
||||
}
|
||||
|
||||
private static void UnbindButton(TerminalButton terminalButton, UnityEngine.Events.UnityAction action)
|
||||
{
|
||||
terminalButton?.Button?.onClick.RemoveListener(action);
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_owner?.SetHeader("<设置>", "MUSIC 50/100 - AUDIO INPUT 001");
|
||||
InitControls();
|
||||
RefreshControls();
|
||||
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show();
|
||||
panelAnimator.Show(prepare: PrepareContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareContent();
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
public void Hide(Action onComplete = null)
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide();
|
||||
panelAnimator.Hide(onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareContent()
|
||||
{
|
||||
_owner?.SetHeader("terminal_header_setting", "REPAIR_STATION_07 - AUTH_VERIFIED");
|
||||
InitControls();
|
||||
RefreshControls();
|
||||
RefreshFooterButtons();
|
||||
}
|
||||
|
||||
private void InitControls()
|
||||
{
|
||||
volumeSlider?.Init("Volume", "音量.....", 0f, 1f, OnSettingChanged);
|
||||
textSpeedOption?.Init("TextSpeed", "文字速度", TextSpeedOptions, OnSettingChanged);
|
||||
windowModeOption?.Init("WindowMode", "屏幕模式", WindowModeOptions, OnSettingChanged);
|
||||
languageOption?.Init("Language", "语言.....", LanguageOptions, OnSettingChanged);
|
||||
volumeSlider?.Init("Volume", "setting_volume", 0f, 1f, OnSettingChanged);
|
||||
textSpeedOption?.Init("TextSpeed", "setting_textSpeed", TextSpeedOptions, OnSettingChanged);
|
||||
windowModeOption?.Init("WindowMode", "setting_window", WindowModeOptions, OnSettingChanged);
|
||||
languageOption?.Init("Language", "setting_language", LanguageOptions, OnSettingChanged);
|
||||
}
|
||||
|
||||
private void RefreshControls()
|
||||
@@ -121,9 +154,37 @@ namespace AibisDream.UI.Terminal
|
||||
SettingLoader.Instance.Write(propName, value);
|
||||
}
|
||||
|
||||
private void RefreshFooterButtons()
|
||||
{
|
||||
var inGame = _owner != null && _owner.IsInGameContext;
|
||||
|
||||
continueButton?.gameObject.SetActive(true);
|
||||
backToMainButton?.gameObject.SetActive(inGame);
|
||||
quitButton?.gameObject.SetActive(inGame);
|
||||
|
||||
ApplyContinueButtonLayout(inGame);
|
||||
}
|
||||
|
||||
private void ApplyContinueButtonLayout(bool inGame)
|
||||
{
|
||||
if (!_hasContinueButtonDefaultPosition || _continueButtonRect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_continueButtonRect.anchoredPosition = inGame
|
||||
? _continueButtonDefaultPosition
|
||||
: new Vector2(0f, _continueButtonDefaultPosition.y);
|
||||
}
|
||||
|
||||
private void BackToGame()
|
||||
{
|
||||
if (_owner.Source == TerminalOpenSource.InGame)
|
||||
if (_owner == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_owner.IsInGameContext)
|
||||
{
|
||||
_owner.Close();
|
||||
}
|
||||
@@ -135,7 +196,7 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
private void BackToMain()
|
||||
{
|
||||
_owner.CloseToMainMenu();
|
||||
_owner?.CloseToMainMenu();
|
||||
}
|
||||
|
||||
private static void QuitApp()
|
||||
|
||||
@@ -4,7 +4,7 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalSliderView : MonoBehaviour
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.UI.Terminal
|
||||
namespace AibisDream.UI
|
||||
{
|
||||
public class TerminalStartPanel : MonoBehaviour
|
||||
{
|
||||
@@ -23,6 +23,7 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
InitMenuItems();
|
||||
RegisterItem(newGameItem, StartNewGame);
|
||||
RegisterItem(chapterItem, OpenChapter);
|
||||
RegisterItem(settingItem, OpenSetting);
|
||||
@@ -39,29 +40,38 @@ namespace AibisDream.UI.Terminal
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_owner?.SetHeader("<选择章节>", "CHAPER xx/xxx - LOADING - DT");
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Show();
|
||||
panelAnimator.Show(prepare: () => _owner?.SetHeader("termnial_header_start", "REPAIR_STATION_07 - AUTH_VERIFIED"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_owner?.SetHeader("termnial_header_start", "REPAIR_STATION_07 - AUTH_VERIFIED");
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
public void Hide(Action onComplete = null)
|
||||
{
|
||||
if (panelAnimator != null)
|
||||
{
|
||||
panelAnimator.Hide();
|
||||
panelAnimator.Hide(onComplete);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
onComplete?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitMenuItems()
|
||||
{
|
||||
newGameItem?.SetContent("start_newGame", "SESSION CREATE", "STATUS: ACTIVE");
|
||||
chapterItem?.SetContent("start_selcetLevel", "HISTORY QUERY", "RANGE: 04/533");
|
||||
settingItem?.SetContent("start_setting", "USER CONFIG", "AUTH: LOCAL");
|
||||
quitItem?.SetContent("start_quit", "SESSION CLOSE", "LOG: SAVED");
|
||||
}
|
||||
|
||||
private void RegisterItem(TerminalMenuItemView item, Action action)
|
||||
{
|
||||
if (item == null)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.UI;
|
||||
using AibisDream.UI.Terminal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
@@ -25,6 +24,7 @@ namespace AibisDream
|
||||
|
||||
private GraphicRaycaster _raycaster;
|
||||
private TerminalPanel _terminalPanel;
|
||||
private InGameTerminalPanel _inGameTerminalPanel;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace AibisDream
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
{
|
||||
if (_inGameTerminalPanel != null && _inGameTerminalPanel.HandleEscape())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_terminalPanel != null && _terminalPanel.HandleEscape())
|
||||
{
|
||||
return;
|
||||
@@ -78,6 +83,7 @@ namespace AibisDream
|
||||
}
|
||||
|
||||
RegisterTerminalPanel();
|
||||
RegisterInGameTerminalPanel();
|
||||
|
||||
EnumEventSystem.Global.Register(GameLoopEnum.AppStart, OnAppStart);
|
||||
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, OnGameStart);
|
||||
@@ -101,7 +107,7 @@ namespace AibisDream
|
||||
return;
|
||||
}
|
||||
|
||||
_terminalPanel.Initialize(Canvas);
|
||||
_terminalPanel.Initialize();
|
||||
if (_terminalPanel.HasRequiredPages())
|
||||
{
|
||||
_panelPool[typeof(TerminalPanel)] = _terminalPanel;
|
||||
@@ -112,6 +118,35 @@ namespace AibisDream
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterInGameTerminalPanel()
|
||||
{
|
||||
if (_panelPool.TryGetValue(typeof(InGameTerminalPanel), out var registeredPanel))
|
||||
{
|
||||
_inGameTerminalPanel = registeredPanel as InGameTerminalPanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
_inGameTerminalPanel = Canvas.GetComponentInChildren<InGameTerminalPanel>(true);
|
||||
}
|
||||
|
||||
if (_inGameTerminalPanel == null)
|
||||
{
|
||||
Debug.LogError("[UIManager] InGameTerminalPanel not found under UI Canvas. Add the in-game terminal shell and assign its Setting/Record prefab pages in the scene.");
|
||||
return;
|
||||
}
|
||||
|
||||
_inGameTerminalPanel.Initialize();
|
||||
var hasPages = _inGameTerminalPanel.HasRequiredPages();
|
||||
if (hasPages)
|
||||
{
|
||||
_panelPool[typeof(InGameTerminalPanel)] = _inGameTerminalPanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[UIManager] InGameTerminalPanel is missing required pages. Assign TerminalSettingPanel and TerminalRecordPanel on the in-game shell.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAppStart()
|
||||
{
|
||||
// 游戏打开
|
||||
@@ -121,6 +156,7 @@ namespace AibisDream
|
||||
HidePanel<MainPanel>();
|
||||
HideTerminalSetting();
|
||||
HideTerminalRecord();
|
||||
_inGameTerminalPanel?.Close();
|
||||
HidePanel<EndPanel>();
|
||||
}
|
||||
|
||||
@@ -128,6 +164,7 @@ namespace AibisDream
|
||||
{
|
||||
// 开始游戏
|
||||
HideTerminal();
|
||||
_inGameTerminalPanel?.Close();
|
||||
ShowPanel<MainPanel>();
|
||||
}
|
||||
|
||||
@@ -213,7 +250,7 @@ namespace AibisDream
|
||||
|
||||
public void ShowTerminalStart()
|
||||
{
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Start, TerminalOpenSource.MainMenu);
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Start);
|
||||
}
|
||||
|
||||
public void HideTerminal()
|
||||
@@ -223,25 +260,26 @@ namespace AibisDream
|
||||
|
||||
public void ShowTerminalSetting()
|
||||
{
|
||||
var source = GameManager.Instance != null && GameManager.Instance.state.isInGame
|
||||
? TerminalOpenSource.InGame
|
||||
: TerminalOpenSource.MainMenu;
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Setting, source);
|
||||
if (GameManager.Instance != null && GameManager.Instance.state.isInGame)
|
||||
{
|
||||
GetPanel<InGameTerminalPanel>()?.Open(InGameTerminalPage.Setting);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Setting);
|
||||
}
|
||||
|
||||
public void HideTerminalSetting()
|
||||
{
|
||||
var terminal = GetPanel<TerminalPanel>();
|
||||
if (terminal == null || !terminal.IsOpen || terminal.CurrentPage != TerminalPage.Setting)
|
||||
var inGame = GetPanel<InGameTerminalPanel>();
|
||||
if (inGame != null && inGame.IsOpen && inGame.CurrentPage == InGameTerminalPage.Setting)
|
||||
{
|
||||
inGame.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (terminal.Source == TerminalOpenSource.InGame)
|
||||
{
|
||||
terminal.Close();
|
||||
}
|
||||
else
|
||||
var terminal = GetPanel<TerminalPanel>();
|
||||
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Setting)
|
||||
{
|
||||
terminal.Back();
|
||||
}
|
||||
@@ -249,7 +287,7 @@ namespace AibisDream
|
||||
|
||||
public void ShowTerminalChapter()
|
||||
{
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Chapter, TerminalOpenSource.MainMenu);
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Chapter);
|
||||
}
|
||||
|
||||
public void HideTerminalChapter()
|
||||
@@ -263,15 +301,16 @@ namespace AibisDream
|
||||
|
||||
public void ShowTerminalRecord()
|
||||
{
|
||||
GetPanel<TerminalPanel>()?.Open(TerminalPage.Record, TerminalOpenSource.InGame);
|
||||
var panel = GetPanel<InGameTerminalPanel>();
|
||||
panel?.Open(InGameTerminalPage.Record);
|
||||
}
|
||||
|
||||
public void HideTerminalRecord()
|
||||
{
|
||||
var terminal = GetPanel<TerminalPanel>();
|
||||
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Record)
|
||||
var inGame = GetPanel<InGameTerminalPanel>();
|
||||
if (inGame != null && inGame.IsOpen && inGame.CurrentPage == InGameTerminalPage.Record)
|
||||
{
|
||||
terminal.Back();
|
||||
inGame.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user