how-to-make-a-video-game-in-unity-game-over-e08

Course: 【油管100w+】 Unity 入门视频


🎮 视频标题|How to make a Video Game in Unity — GAME OVER (E08)

👤 主讲人|Brackeys

📅 系列定位|Unity 初学者系列 Episode 08

🏷 关键词|GameManager | Restart | SceneManager | Invoke | 布尔状态 | Game Over | Delay


🏛 课程目标

为游戏添加一个“游戏结束与重启系统”,

当玩家撞上障碍或掉出地图时,游戏延迟几秒后自动重启。


🧭 核心思路

1️⃣ 用一个新的脚本 GameManager 负责管理游戏状态。

2️⃣ 当玩家死亡(碰撞或坠落)时调用 EndGame()

3️⃣ 延迟几秒后通过 SceneManager.LoadScene() 重新加载当前关卡。


📦 创建 GameManager 系统

1️⃣ Hierarchy → 右键 → Create Empty → 命名为 GameManager

2️⃣ Reset Transform(保持干净)

3️⃣ 点击 “Add Component” → 新建脚本 → 命名为 GameManager


🧠 GameManager.cs 初版

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public void EndGame()
    {
        Debug.Log("Game Over");
    }
}

📘 public 关键字允许在其他脚本中访问该函数。

先用 Debug.Log() 打印信息验证是否触发。


📚 在 PlayerCollision 中调用 GameManager

目前碰撞逻辑在 PlayerCollision.cs 中:

if (collisionInfo.collider.tag == "Obstacle")
{
    movement.enabled = false;
    // TODO: 调用 GameManager.EndGame()
}

直接引用会导致预制体引用丢失问题。

👉 解决方案:动态查找对象。

FindObjectOfType<GameManager>().EndGame();

Unity 会在场景中搜索第一个挂有 GameManager 脚本的对象并调用方法。

虽然效率略低,但简单安全。


🧩 引用变量丢失原因

当 Player 被制作成 Prefab 并重新拖回场景时,

Inspector 中的手动引用会丢失。

通过 FindObjectOfType<> 可避免这种情况,无需手动拖引用。

⚠️ 注意:性能低于直接引用,仅在需要动态实例化对象时使用。


📦 让玩家掉落时也触发游戏结束

PlayerMovement.cs 中添加以下代码:

void FixedUpdate()
{
    if (rb.position.y < -1f)
    {
        FindObjectOfType<GameManager>().EndGame();
    }
}
  • 检查 Y 坐标是否低于阈值(-1 表示掉出地图)
  • 掉落时自动调用 Game Over

📘 Unity 中 FixedUpdate() 是物理计算帧函数,

因此适合检测基于 Rigidbody 的坐标变化。


🧪 防止重复调用多次 EndGame()

如果玩家连续掉落或多次触发碰撞,会出现多次重启。

→ 使用布尔变量限制只执行一次。

bool gameHasEnded = false;

public void EndGame()
{
    if (gameHasEnded == false)
    {
        gameHasEnded = true;
        Debug.Log("Game Over");
        Restart();
    }
}

✅ 确保只执行一次。

🧩 “状态锁”机制是游戏逻辑中常见的防抖方法。


📚 实现关卡重启逻辑

在 GameManager.cs 末尾添加:

using UnityEngine.SceneManagement;

public float restartDelay = 1f;

void Restart()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
  • SceneManager.GetActiveScene().name:返回当前活动场景名称。
  • SceneManager.LoadScene():重新加载该场景实现“重开游戏”。

🧠 添加延迟重启效果

直接调用重启太快,看起来突兀。

Unity 提供 Invoke() 延迟执行函数:

public void EndGame()
{
    if (!gameHasEnded)
    {
        gameHasEnded = true;
        Debug.Log("Game Over");
        Invoke("Restart", restartDelay);
    }
}

🎯 Invoke(“方法名”, 延迟时间) 可让游戏在几秒后执行操作。

这里的 restartDelay 默认为 1 秒,可在 Inspector 调整。


完整 GameManager.cs

using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    bool gameHasEnded = false;
    public float restartDelay = 1f;

    public void EndGame()
    {
        if (!gameHasEnded)
        {
            gameHasEnded = true;
            Debug.Log("Game Over");
            Invoke("Restart", restartDelay);
        }
    }

    void Restart()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

📘 逻辑流程:

1️⃣ 检测游戏结束

2️⃣ 锁定状态(防止重复)

3️⃣ 延迟重启

4️⃣ 重新加载当前关卡


📦 小问题:重新加载后光照变灰

原因:Lighting → “Auto Generate” 选项。

当场景在编辑器中重新加载时,Unity 没时间重建光照。

✅ 解决方法:

  • 打开 Window → Rendering → Lighting Settings
  • 取消勾选 Auto Generate
  • 点击 “Generate Lighting” 手动构建。

生产环境推荐关闭 Auto,提高加载一致性。


📚 Build Settings 检查

若重启时报错:

“Scene not in build settings”

解决:

  • File → Build Settings → “Add Open Scenes”
  • 确保当前关卡在构建列表中。
  • 多关卡项目可按 Build Index 管理场景切换。

本集成果总结

模块功能
GameManager管理全局游戏状态
EndGame()控制游戏结束触发
Invoke()延迟调用重启
SceneManager加载当前或下个场景
布尔锁防止多次执行逻辑
Lighting 调整修复自动光照闪烁

🪄 延伸练习

1️⃣ 添加 GameOverUI → 在游戏结束时显示文字而非立即重启。

2️⃣ 将重启绑定到按钮点击事件 (OnClick → GameManager.Restart())。

3️⃣ 结合分数系统(E07),在 Game Over 界面显示最终得分。

4️⃣ 添加动画淡出效果或背景音乐停止逻辑。


📚 下一集预告:Final Polish & Build

Episode 09 将进入游戏收尾阶段,

添加主菜单、结束画面与打包导出流程。

你将学习:

  • UI Button 点击事件
  • 多场景切换
  • 游戏最终打包设置