昨天完成了分數系統,不過實際遊玩時發現,遊戲還是少了一個比較完整的開始與結束流程。目前只要進入遊戲,小鳥就會直接開始掉落,死亡後也只有停止遊戲,沒有一個正式的結算畫面。所以今天就開始製作遊戲的狀態管理,讓遊戲變成「等待開始→遊戲進行→遊戲結束→重新開始」的流程。
這次先建立GameManager,用三種狀態來判斷遊戲目前進行到哪裡:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public enum GameState
{
WaitingToStart, // 等待玩家點擊畫面開始
Playing, // 遊戲進行中
GameOver // 遊戲結束(顯示結算 UI)
}
[Header("當前遊戲狀態")]
public GameState currentState = GameState.WaitingToStart;
[Header("UI 面板設定")]
[Tooltip("結算畫面的 Panel/Image 容器")]
public GameObject gameOverPanel;
[Tooltip("結算畫面中央顯示本次分數的 Text")]
public TMP_Text finalScoreText;
[Tooltip("結算畫面右上角顯示最高分數的 Text")]
public TMP_Text gameOverHighScoreText;
[Tooltip("開局提示點擊文字(例如:Tap to Start),可選")]
public GameObject startHintUI;
private static bool isRestarting = false; // 紀錄是否剛按下「重新開始」
void Awake()
{
if (Instance == null) Instance = this;
else Destroy(gameObject);
}
void Start()
{
// 剛進入遊戲或重新載入時,凍結時間或暫停生成
Time.timeScale = 0f; // 暫停遊戲時間,使小鳥與障礙物靜止
currentState = GameState.WaitingToStart;
if (gameOverPanel != null) gameOverPanel.SetActive(false);
if (startHintUI != null) startHintUI.SetActive(true);
}
void Update()
{
// 若處於等待開始狀態,點擊畫面/鍵盤即可開始
if (currentState == GameState.WaitingToStart)
{
bool isComputerInput = Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0);
bool isMobileInput = Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began;
if (isComputerInput || isMobileInput)
{
StartGame();
}
}
}
// 正式開始遊戲
public void StartGame()
{
currentState = GameState.Playing;
Time.timeScale = 1f; // 恢復正常遊戲速度
if (startHintUI != null) startHintUI.SetActive(false);
// 通知分數系統開始計分
if (ScoreManager.Instance != null)
{
ScoreManager.Instance.StartScoring();
}
// 通知小鳥執行開局的第一跳
BirdController bird = FindObjectOfType<BirdController>();
if (bird != null)
{
bird.OnGameStartJump();
}
}
// 小鳥死亡時呼叫:觸發結算 UI
public void OnGameOver()
{
currentState = GameState.GameOver;
// 停止計分並獲取最終分數
if (ScoreManager.Instance != null)
{
ScoreManager.Instance.StopScoring();
int finalScore = ScoreManager.Instance.GetFinalScore();
int highScore = PlayerPrefs.GetInt("HighScore", 0);
if (finalScoreText != null) finalScoreText.text = finalScore.ToString("D6");
if (gameOverHighScoreText != null) gameOverHighScoreText.text = "BEST: " + highScore.ToString("D6");
}
// 顯示結算畫面
if (gameOverPanel != null)
{
gameOverPanel.SetActive(true);
}
}
// 按下結算畫面的「重新開始」按鈕時呼叫
public void OnRestartButtonClick()
{
Time.timeScale = 1f; // 恢復時間刻度以利重置
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); // 重新載入當前場景
}
}
這裡主要是利用Time.timeScale = 0讓遊戲一開始先暫停,等玩家點擊後才恢復遊戲。
開始遊戲時也會通知ScoreManager開始計分,並讓小鳥執行第一次跳躍。
有了遊戲狀態後,小鳥也需要判斷現在是不是正在遊戲中。原本只要點擊畫面就會跳躍,所以這裡修改成只有Playing狀態才能正常跳躍。
void Update()
{
// 【修改】若小鳥死亡,或遊戲尚未開始(WaitingToStart/GameOver),不響應普通跳躍輸入
if (isDead || GameManager.Instance == null || GameManager.Instance.currentState != GameManager.GameState.Playing)
return;
// 防範 UI 穿透點擊(點擊技能鍵時不觸發背景普通跳躍)
if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject())
{
return;
}
bool isComputerInput = Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0);
bool isMobileInput = Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began;
if (isComputerInput || isMobileInput)
{
Jump();
}
}
// 【新增】專門給 GameManager 在點擊開局時呼叫的第一跳
public void OnGameStartJump()
{
Jump();
}
另外新增OnGameStartJump(),讓GameManager在遊戲開始時控制小鳥進行第一次跳躍。
死亡時則改成通知GameManager:
void Die()
{
if (isDead) return;
isDead = true;
Debug.Log("小鳥撞到了!遊戲結束。");
// 【修改】呼叫 GameManager 觸發結算流程與 UI
if (GameManager.Instance != null)
{
GameManager.Instance.OnGameOver();
}
}
這樣撞到岩石後,就會正式進入GameOver狀態。
最後也修改了ScoreManager的Start(),讓每次重新載入遊戲時,分數重新從零開始。
void Start()
{
rockSpawner = FindObjectOfType<RockSpawner>();
currentScoreRaw = 0f;
isScoring = false; // 初始不計分,等待 GameManager 發出 StartScoring 訊號
}
這樣重新開始後,本局分數會重新計算,但之前使用 PlayerPrefs 保存的最高分仍然會保留。
整個流程就變成:
等待開始→玩家點擊→開始遊戲→開始計分→小鳥死亡→停止計分→顯示本次分數與最高分→重新開始→分數重新計算
今天主要完成了遊戲的開始與結算流程。現在進入遊戲後不會直接開始,而是等待玩家點擊;死亡後也會顯示本次分數與最高分,按下重新開始後則會重新載入遊戲。
由於剩下天數不多,下一款遊戲應該會製作簡單一點的。