摄像机区域的架构改动
This commit is contained in:
21
Assets/_Game/Scripts/Tutorial/BaseGames.Tutorial.asmdef
Normal file
21
Assets/_Game/Scripts/Tutorial/BaseGames.Tutorial.asmdef
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"precompiledReferences": [],
|
||||
"name": "BaseGames.Tutorial",
|
||||
"defineConstraints": [],
|
||||
"noEngineReferences": false,
|
||||
"versionDefines": [],
|
||||
"rootNamespace": "BaseGames.Tutorial",
|
||||
"references": [
|
||||
"BaseGames.Core.Events",
|
||||
"BaseGames.Core.Save",
|
||||
"BaseGames.World",
|
||||
"BaseGames.Player",
|
||||
"BaseGames.Localization",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"autoReferenced": true,
|
||||
"overrideReferences": false,
|
||||
"includePlatforms": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69e13da9aec864e4dad1e8db7d75f12d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
Assets/_Game/Scripts/Tutorial/ContextualHintTrigger.cs
Normal file
53
Assets/_Game/Scripts/Tutorial/ContextualHintTrigger.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Player;
|
||||
using BaseGames.Localization;
|
||||
|
||||
namespace BaseGames.Tutorial
|
||||
{
|
||||
/// <summary>
|
||||
/// 情境化教程触发器(架构 21_LiquidPuzzleModule §18)。
|
||||
/// 当玩家进入 Trigger 碰撞体范围时,向 TutorialManager 请求显示提示。
|
||||
/// 若 _requiresAbility = true,只在玩家拥有 _requiredAbility 后才触发。
|
||||
/// 每个触发器只触发一次(触发后禁用自身)。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
public class ContextualHintTrigger : MonoBehaviour
|
||||
{
|
||||
[Header("提示配置")]
|
||||
[SerializeField] private string _hintId = "";
|
||||
[SerializeField] private string _hintLocKey = ""; // 本地化 Key(Table_UI)
|
||||
[SerializeField] private float _displayDuration = 4f;
|
||||
|
||||
[Header("能力门控")]
|
||||
[SerializeField] private bool _requiresAbility = false;
|
||||
[SerializeField] private AbilityType _requiredAbility = AbilityType.None;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
var col = GetComponent<Collider2D>();
|
||||
col.isTrigger = true;
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
if (!other.CompareTag("Player")) return;
|
||||
var tm = ServiceLocator.GetOrDefault<ITutorialService>();
|
||||
if (tm == null) return;
|
||||
|
||||
// 能力门控检查
|
||||
if (_requiresAbility)
|
||||
{
|
||||
var stats = other.GetComponent<PlayerStats>();
|
||||
if (stats == null || !stats.HasAbility(_requiredAbility)) return;
|
||||
}
|
||||
|
||||
string text = LocalizationManager.Get(_hintLocKey, "UI");
|
||||
tm.ShowHint(_hintId, text, _displayDuration);
|
||||
tm.CompleteHint(_hintId); // 写入 SaveData,防止场景重载后重复触发
|
||||
|
||||
// 单次触发后禁用(避免重复弹出)
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Tutorial/ContextualHintTrigger.cs.meta
Normal file
11
Assets/_Game/Scripts/Tutorial/ContextualHintTrigger.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f67c909769494146962903acf3a0a45
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Assets/_Game/Scripts/Tutorial/ITutorialService.cs
Normal file
17
Assets/_Game/Scripts/Tutorial/ITutorialService.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace BaseGames.Tutorial
|
||||
{
|
||||
/// <summary>
|
||||
/// 教程提示服务接口。通过 ServiceLocator 注册,供触发器和测试使用。
|
||||
/// </summary>
|
||||
public interface ITutorialService
|
||||
{
|
||||
/// <summary>显示提示。若 hintId 已完成则忽略。</summary>
|
||||
void ShowHint(string hintId, string text, float duration = 4f);
|
||||
|
||||
/// <summary>标记提示为已完成并隐藏当前显示中的提示。</summary>
|
||||
void CompleteHint(string hintId);
|
||||
|
||||
/// <summary>查询指定提示是否已完成。</summary>
|
||||
bool IsHintCompleted(string hintId);
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Tutorial/ITutorialService.cs.meta
Normal file
11
Assets/_Game/Scripts/Tutorial/ITutorialService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 648235b6e78784a43b04c1eff4889fcc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
54
Assets/_Game/Scripts/Tutorial/TutorialHintUI.cs
Normal file
54
Assets/_Game/Scripts/Tutorial/TutorialHintUI.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
namespace BaseGames.Tutorial
|
||||
{
|
||||
/// <summary>
|
||||
/// 教程提示 UI 组件(架构 21_LiquidPuzzleModule §17)。
|
||||
/// 负责显示/隐藏提示面板和文字;duration ≤ 0 时不自动消隐。
|
||||
/// </summary>
|
||||
public class TutorialHintUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameObject _panel;
|
||||
[SerializeField] private TMP_Text _label;
|
||||
#pragma warning disable CS0414
|
||||
[SerializeField] private float _fadeSpeed = 4f;
|
||||
#pragma warning restore CS0414
|
||||
|
||||
private Coroutine _autoHideCoroutine;
|
||||
|
||||
// ── 公共 API ──────────────────────────────────────────────────────
|
||||
/// <summary>显示提示文字。duration ≤ 0 时不自动消隐。</summary>
|
||||
public void Show(string text, float duration = 0f)
|
||||
{
|
||||
if (_panel != null) _panel.SetActive(true);
|
||||
if (_label != null) _label.text = text;
|
||||
|
||||
if (_autoHideCoroutine != null)
|
||||
StopCoroutine(_autoHideCoroutine);
|
||||
|
||||
if (duration > 0f)
|
||||
_autoHideCoroutine = StartCoroutine(AutoHideRoutine(duration));
|
||||
}
|
||||
|
||||
/// <summary>立即隐藏提示面板。</summary>
|
||||
public void Hide()
|
||||
{
|
||||
if (_autoHideCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_autoHideCoroutine);
|
||||
_autoHideCoroutine = null;
|
||||
}
|
||||
if (_panel != null) _panel.SetActive(false);
|
||||
}
|
||||
|
||||
// ── 内部 ──────────────────────────────────────────────────────────
|
||||
private IEnumerator AutoHideRoutine(float duration)
|
||||
{
|
||||
yield return new WaitForSeconds(duration);
|
||||
Hide();
|
||||
_autoHideCoroutine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Tutorial/TutorialHintUI.cs.meta
Normal file
11
Assets/_Game/Scripts/Tutorial/TutorialHintUI.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f4b9a32b1daa14fa837c1938b34310
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
86
Assets/_Game/Scripts/Tutorial/TutorialManager.cs
Normal file
86
Assets/_Game/Scripts/Tutorial/TutorialManager.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using BaseGames.Core.Save;
|
||||
|
||||
namespace BaseGames.Tutorial
|
||||
{
|
||||
/// <summary>
|
||||
/// 教程提示管理器(架构 21_LiquidPuzzleModule §17)。
|
||||
/// 通过 ServiceLocator 注册,实现 ISaveable 将已完成提示 ID 持久化。
|
||||
/// ShowHint:若 ID 已完成则跳过;否则显示,并在 duration 秒后自动隐藏。
|
||||
/// CompleteHint:标记为已完成,写回 SaveData。
|
||||
/// </summary>
|
||||
public class TutorialManager : MonoBehaviour, ISaveable, ITutorialService
|
||||
{
|
||||
[SerializeField] private TutorialHintUI _hintUI;
|
||||
|
||||
private readonly HashSet<string> _completedHints = new();
|
||||
|
||||
// ── Unity 生命周期 ────────────────────────────────────
|
||||
private void Awake()
|
||||
{
|
||||
if (BaseGames.Core.ServiceLocator.GetOrDefault<ITutorialService>() != null) { Destroy(gameObject); return; }
|
||||
BaseGames.Core.ServiceLocator.Register<ITutorialService>(this);
|
||||
// 生命周期由 Persistent 场景根 GameObject 统一管理,不在此调用 DontDestroyOnLoad
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
BaseGames.Core.ServiceLocator.Unregister<ITutorialService>(this);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
BaseGames.Core.ServiceLocator.GetOrDefault<BaseGames.Core.Save.ISaveableRegistry>()?.Register(this);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
BaseGames.Core.ServiceLocator.GetOrDefault<BaseGames.Core.Save.ISaveableRegistry>()?.Unregister(this);
|
||||
}
|
||||
|
||||
// ── 公共 API ──────────────────────────────────────────────────────
|
||||
/// <summary>
|
||||
/// 显示提示。若 hintId 已完成则忽略。
|
||||
/// <paramref name="hintId"/>: 唯一提示 ID(可作为去重键和保存键)。
|
||||
/// <paramref name="text"/>: 本地化后的显示文字。
|
||||
/// <paramref name="duration"/>: 自动消隐秒数(≤ 0 则不自动消隐)。
|
||||
/// </summary>
|
||||
public void ShowHint(string hintId, string text, float duration = 4f)
|
||||
{
|
||||
if (_completedHints.Contains(hintId)) return;
|
||||
if (_hintUI == null) return;
|
||||
_hintUI.Show(text, duration);
|
||||
}
|
||||
|
||||
/// <summary>标记提示为已完成,并自动隐藏当前显示中的提示。</summary>
|
||||
public void CompleteHint(string hintId)
|
||||
{
|
||||
if (_completedHints.Add(hintId))
|
||||
{
|
||||
_hintUI?.Hide();
|
||||
// 持久化由 ISaveable.OnSave 统一处理,此处仅更新内存状态
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>查询指定提示是否已完成。</summary>
|
||||
public bool IsHintCompleted(string hintId) => _completedHints.Contains(hintId);
|
||||
|
||||
// ── ISaveable ─────────────────────────────────────────────────────
|
||||
public void OnSave(SaveData data)
|
||||
{
|
||||
if (data?.Tutorial == null) return;
|
||||
data.Tutorial.CompletedHintIds.Clear();
|
||||
data.Tutorial.CompletedHintIds.AddRange(_completedHints);
|
||||
}
|
||||
|
||||
public void OnLoad(SaveData data)
|
||||
{
|
||||
_completedHints.Clear();
|
||||
if (data?.Tutorial == null) return;
|
||||
foreach (var id in data.Tutorial.CompletedHintIds)
|
||||
_completedHints.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Tutorial/TutorialManager.cs.meta
Normal file
11
Assets/_Game/Scripts/Tutorial/TutorialManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6f587df338c06c4184832700fc8101d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user