增加怪物功能,调整灵灯参数
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: DXwf4C6kWniDTHsh4b3aQIGvTSikXkx4eRJzW2U7bhl8SN5cR5j/4FI=
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user