Unity Term Book
核心与架构

Scene

Scene 是容纳所有 GameObject、灯光与摄像机的空间——每个 .unity 文件就是一个 Scene:关卡、菜单或独立游戏状态。用 SceneManager 切换场景,LoadSceneAsync 可配加载界面;DontDestroyOnLoad 让跨关卡对象存活。它是 Unity 项目管理与流程设计骨架。

想象一下...

Scene 就像一集电视剧。每一集有自己的布景、角色和剧情。切到下一集(加载 Scene)时,旧布景消失。需要跨集存活的角色用 DontDestroyOnLoad()——像主角,关卡切换也从不消失。

概念详解

典型游戏有许多 Scene: MainMenu、Level_01、Level_02、GameOver、Loading… 拆分 它们有助于控制内存——只加载当前需要的内容。

切换 Scene 使用 SceneManager 类。LoadScene() 是同步的 (会阻塞——游戏卡住),而 LoadSceneAsync() 在后台加载,方便 显示 Loading Screen。

Additive Loading:同时加载多个 Scene,彼此叠加。 常用于世界流式加载,或把 UI Scene 与玩法 Scene 拆开。

需要跨 Scene 存活的 GameObject 使用 DontDestroyOnLoad(gameObject)。务必 配合 Singleton,避免 Scene 重载时再生成一份副本。

Scene 流程

🎬

MainMenu

index: 0

Loading

index: 1

🎮

Level_01

index: 2

💀

GameOver

index: 3

Single Mode

加载新 Scene → 卸载旧 Scene

Additive Mode

额外加载 → 保留旧 Scene

动手步骤

1

创建新 Scene

菜单 File → New Scene 创建 Scene。

2

加入 Build Settings

File → Build Settings → 把 .unity 文件拖进列表。索引号就是 LoadScene(index) 用的数字。

3

用脚本切换 Scene

加上 using UnityEngine.SceneManagement;,再调用 SceneManager.LoadScene()

4

用 Async 做 Loading Screen

用 Coroutine + LoadSceneAsync(),读取 AsyncOperation.progress(0.0 → 0.9)更新进度条。

交互模拟器

点击 Load Scene 模拟带 Loading Screen 的切换。观察 GameManager 如何跨 Scene 存活。

Build Settings

🔒 GameManager

DontDestroyOnLoad

Active Scene: MainMenu ·  Build Index: 0

代码示例

基础
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneBasics : MonoBehaviour
{
  void Awake()
  {
      // Keep this object across every Scene (Singleton GameManager)
      DontDestroyOnLoad(gameObject);
  }

  public void LoadLevel1()
      => SceneManager.LoadScene("Level_01");      // by name

  public void RestartCurrentScene()
  {
      int idx = SceneManager.GetActiveScene().buildIndex;
      SceneManager.LoadScene(idx);                   // by index
  }

  public void LoadNextScene()
  {
      int next = SceneManager.GetActiveScene().buildIndex + 1;
      SceneManager.LoadScene(next);
  }
}

代码示例

进阶
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneLoader : MonoBehaviour
{
  public static SceneLoader Instance { get; private set; }
  [SerializeField] private Slider progressBar;

  void Awake()
  {
      // Singleton: only one instance may exist
      if (Instance != null) { Destroy(gameObject); return; }
      Instance = this;
      DontDestroyOnLoad(gameObject);
  }

  public void LoadScene(string sceneName)
      => StartCoroutine(LoadAsync(sceneName));

  private IEnumerator LoadAsync(string sceneName)
  {
      AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
      op.allowSceneActivation = false;

      while (op.progress < 0.9f)
      {
          float progress = Mathf.Clamp01(op.progress / 0.9f);
          if (progressBar) progressBar.value = progress;
          yield return null;
      }

      if (progressBar) progressBar.value = 1f;
      yield return new WaitForSeconds(0.5f);
      op.allowSceneActivation = true;
  }
}

📌 快速记忆

  • Scene 必须先加入 Build Settings,LoadScene 才能找到
  • DontDestroyOnLoad 让对象跨切换存活
  • 用 Async + Coroutine 做 Loading Screen
  • Additive 模式用于世界流式加载和拆分 UI

⚠️ 常见错误

  • ❌ 忘记把 Scene 加入 Build Settings

    报错 "Scene not found in Build Settings"

    ✅ File → Build Settings → Add Open Scenes

  • ❌ DontDestroyOnLoad 却没有 Singleton 守卫

    重载 Scene 会生成第二个 GameManager

    ✅ if (Instance != null) Destroy(this);