增加怪物功能,调整灵灯参数

This commit is contained in:
2026-07-03 16:06:18 +08:00
parent e75868832f
commit 6e414a3022
46 changed files with 5907 additions and 300 deletions
+130
View File
@@ -0,0 +1,130 @@
using UnityEngine;
using UnityEngine.UI;
using IndianOceanAssets.Engine2_5D;
using GameFramework;
namespace GameFramework
{
/// <summary>
/// 游戏内 HUD —— 显示血量、灵灯数量/CD、分数、暂停按钮。
/// 挂在 Gameplay 场景的 HUD Canvas 上。
/// </summary>
public class GameHUD : MonoBehaviour
{
[Header("血量")]
[SerializeField] private Slider healthSlider;
[SerializeField] private Text healthText;
[Header("灵灯")]
[SerializeField] private Text lanternCountText;
[SerializeField] private Text lanternCDText;
[SerializeField] private Image lanternCDFill; // 可选:CD 圆形填充
[Header("分数")]
[SerializeField] private Text scoreText;
[Header("暂停")]
[SerializeField] private Button pauseButton;
private HealthSystem _playerHealth;
private SpiritLanternSystem _lanternSystem;
private int _maxHealth;
void Start()
{
// 查找玩家
var player = GameObject.FindWithTag("Player");
if (player != null)
{
_playerHealth = player.GetComponent<HealthSystem>();
_lanternSystem = player.GetComponent<SpiritLanternSystem>();
// 获取 maxHealth
if (_playerHealth != null)
{
var field = typeof(HealthSystem).GetField("maxHealth",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (field != null)
_maxHealth = (int)field.GetValue(_playerHealth);
else
_maxHealth = 100;
}
}
// 绑定暂停按钮
if (pauseButton != null)
pauseButton.onClick.AddListener(OnPauseClick);
// 订阅分数事件
ScoreManager.onScoreChanged += UpdateScore;
// 初始更新
UpdateScore(ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0);
}
void OnDestroy()
{
ScoreManager.onScoreChanged -= UpdateScore;
}
void Update()
{
UpdateHealth();
UpdateLantern();
}
private void UpdateHealth()
{
if (_playerHealth == null) return;
// 获取当前血量
var field = typeof(HealthSystem).GetField("health",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int currentHealth = field != null ? (int)field.GetValue(_playerHealth) : _maxHealth;
if (healthSlider != null)
healthSlider.value = (float)currentHealth / _maxHealth;
if (healthText != null)
healthText.text = $"{currentHealth}/{_maxHealth}";
}
private void UpdateLantern()
{
if (_lanternSystem == null) return;
if (lanternCountText != null)
lanternCountText.text = $"灵灯: {_lanternSystem.RemainingLanterns}";
if (lanternCDText != null)
{
if (_lanternSystem.IsCooldownReady)
lanternCDText.text = "就绪";
else
lanternCDText.text = $"{_lanternSystem.CooldownRemaining:F1}s";
}
if (lanternCDFill != null)
{
// CD 填充:就绪时满,冷却中递减
var cdField = typeof(SpiritLanternSystem).GetField("cooldown",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
float maxCD = cdField != null ? (float)cdField.GetValue(_lanternSystem) : 3f;
lanternCDFill.fillAmount = _lanternSystem.IsCooldownReady ? 1f :
1f - (_lanternSystem.CooldownRemaining / maxCD);
}
}
private void UpdateScore(int score)
{
if (scoreText != null)
scoreText.text = $"分数: {score}";
}
private void OnPauseClick()
{
if (TimeController.Instance != null)
TimeController.Instance.Pause();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DXwf4C6kWniDTHsh4b3aQIGvTSikXkx4eRJzW2U7bhl8SN5cR5j/4FI=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+15 -3
View File
@@ -5,13 +5,16 @@ namespace GameFramework
{
/// <summary>
/// 全局游戏状态管理器(持久化单例)。
/// 维护 GameState,提供 GameOver 触发入口与 onGameOver 事件。
/// 维护 GameState,提供 GameOver / Win 触发入口与对应事件。
/// </summary>
public class GameManager : PersistentSingleton<GameManager>
{
/// <summary>游戏结束时触发GameOverScreen 等订阅)。</summary>
/// <summary>游戏结束(失败)时触发。</summary>
public static Action onGameOver;
/// <summary>游戏胜利时触发。</summary>
public static Action onGameWin;
public static GameState GameState
{
get => Instance.gameState;
@@ -20,13 +23,21 @@ namespace GameFramework
[SerializeField] private GameState gameState = GameState.Playing;
/// <summary>触发游戏结束:设状态 + 触发事件。玩家被敌人抓到时调用。</summary>
/// <summary>触发游戏失败:设状态 + 触发事件。</summary>
public static void GameOver()
{
if (Instance == null) return;
GameState = GameState.GameOver;
onGameOver?.Invoke();
}
/// <summary>触发游戏胜利:设状态 + 触发事件。</summary>
public static void Win()
{
if (Instance == null) return;
GameState = GameState.Victory;
onGameWin?.Invoke();
}
}
public enum GameState
@@ -34,6 +45,7 @@ namespace GameFramework
Playing,
Paused,
GameOver,
Victory,
Scoring
}
}
+142
View File
@@ -0,0 +1,142 @@
using UnityEngine;
using UnityEngine.UI;
namespace GameFramework
{
/// <summary>
/// 游戏结果类型。
/// </summary>
public enum GameResult { Win, Lose }
/// <summary>
/// 游戏结果界面(支持胜利/失败)。
/// 监听 GameManager.onGameOver 和 onGameWin 事件,
/// 显示对应面板并暂停游戏。确认后跳转到排行榜场景。
/// </summary>
public class GameResultScreen : MonoBehaviour
{
[Header("Canvas")]
[SerializeField] private Canvas resultCanvas;
[Header("胜利面板")]
[SerializeField] private GameObject winPanel;
[SerializeField] private Button winConfirmButton;
[SerializeField] private Text winTitleText;
[SerializeField] private Text winScoreText;
[Header("失败面板")]
[SerializeField] private GameObject losePanel;
[SerializeField] private Button loseConfirmButton;
[SerializeField] private Text loseTitleText;
[SerializeField] private Text loseScoreText;
[Header("Audio")]
[SerializeField] private AudioData winSFX;
[SerializeField] private AudioData loseSFX;
[Header("Input")]
[SerializeField] private KeyCode confirmKey = KeyCode.Return;
private bool _isVisible;
void OnEnable()
{
GameManager.onGameOver += OnGameOver;
GameManager.onGameWin += OnGameWin;
}
void OnDisable()
{
GameManager.onGameOver -= OnGameOver;
GameManager.onGameWin -= OnGameWin;
}
void OnGameOver() => ShowResult(GameResult.Lose);
void OnGameWin() => ShowResult(GameResult.Win);
void Start()
{
// 初始隐藏
if (resultCanvas != null)
resultCanvas.enabled = false;
// 绑定按钮
if (winConfirmButton != null)
winConfirmButton.onClick.AddListener(OnConfirmClick);
if (loseConfirmButton != null)
loseConfirmButton.onClick.AddListener(OnConfirmClick);
}
/// <summary>
/// 显示游戏结果界面。
/// </summary>
public void ShowResult(GameResult result)
{
_isVisible = true;
// 显示 Canvas
if (resultCanvas != null)
resultCanvas.enabled = true;
// 更新分数显示
int score = ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0;
if (result == GameResult.Win)
{
// 显示胜利面板,隐藏失败面板
if (winPanel != null) winPanel.SetActive(true);
if (losePanel != null) losePanel.SetActive(false);
if (winScoreText != null) winScoreText.text = $"分数: {score}";
if (winConfirmButton != null) winConfirmButton.Select();
if (AudioManager.Instance != null && winSFX != null)
AudioManager.Instance.PlaySFX(winSFX);
}
else
{
// 显示失败面板,隐藏胜利面板
if (winPanel != null) winPanel.SetActive(false);
if (losePanel != null) losePanel.SetActive(true);
if (loseScoreText != null) loseScoreText.text = $"分数: {score}";
if (loseConfirmButton != null) loseConfirmButton.Select();
if (AudioManager.Instance != null && loseSFX != null)
AudioManager.Instance.PlaySFX(loseSFX);
}
// 暂停游戏
if (TimeController.Instance != null)
TimeController.Instance.Pause();
// 显示鼠标
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
void Update()
{
if (!_isVisible) return;
// 按确认键跳转
if (Input.GetKeyDown(confirmKey) || Input.GetKeyDown(KeyCode.Space))
{
OnConfirmClick();
}
}
void OnConfirmClick()
{
_isVisible = false;
// 解除暂停
if (TimeController.Instance != null)
TimeController.Instance.Unpause();
// 跳转到排行榜
if (SceneLoader.Instance != null)
SceneLoader.Instance.LoadScoringScene();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ByhOtHykUH+NM7CefkS+HawWqQ4AJs073f/1lhK5Y3Ch+eoeqXyFIYk=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+5 -2
View File
@@ -4,11 +4,14 @@ using UnityEngine.UI;
namespace GameFramework
{
/// <summary>
/// 主菜单 UI 控制器。
/// 绑定三个按钮:开始游戏(异步加载)、设置(占位面板)、退出游戏
/// 主菜单 UI 控制器(游戏封面)
/// 包含游戏标题 + 开始/设置/退出按钮
/// </summary>
public class MainMenuUIController : MonoBehaviour
{
[Header("标题")]
[SerializeField] Text titleText;
[Header("Buttons")]
[SerializeField] Button startButton;
[SerializeField] Button settingsButton;