32.Unity入门实践项目总结

  1. 32.总结
    1. 32.1 知识点
      1. 学习的主要内容
      2. 总结目的
      3. Unity做游戏的套路
      4. 如何学好Unity
      5. 达到目的
      6. 练习
    2. 32.2 核心要点速览
      1. 场景切换与退出
      2. 鼠标光标与 Cursor API
      3. 随机数与委托
      4. 模型资源导入
      5. 坦克迷宫:项目概述与需求
        1. 前置知识
        2. 功能需求
        3. 实现主线
      6. 工程依赖包
      7. 开始场景装饰
      8. 面板基类与开始 / 设置
      9. 音效数据与 GameDataMgr
      10. 排行榜数据与面板
      11. 背景音乐 BKMusic
      12. 游戏场景:地形、HUD、暂停
      13. 坦克基类 TankBaseObj
      14. 玩家坦克 PlayerObj
      15. 小地图摄像机
      16. 武器与子弹
      17. 武器奖励与自动销毁
      18. 属性奖励 PropReward
      19. 可击毁箱子 CubeObj
      20. 固定炮塔 MonsterTower
      21. 移动敌人 MonsterObj
      22. 通关与胜败界面
      23. 构建与 Player 设置
    3. 32.3 面试题精选
      1. 进阶题
        1. 1. SceneManager.LoadScene 运行时失败常见原因?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. CursorLockMode.Locked 与 Confined 各解决什么问题?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. Random.Range 的 int 与 float 重载在区间边界上有何不同?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. BasePanel<T> 为何要 where T : class,单例在 Awake 里怎么拿到具体面板类型?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        5. 5. RankPanel 里用 transform.Find("Name/labName" + i) 取控件,路径里斜杠表示什么?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        6. 6. GameDataMgr 构造里为何用 notFirst 判断并写回默认音量?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        7. 7. TankBaseObj.Wound 里 dmg = atk - def,dmg <= 0 时为何直接 return?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        8. 8. 子弹 OnTriggerEnter 如何用 Player / Monster Tag 做阵营过滤?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        9. 9. PlayerObj 重写 Dead 时为何不调用 base.Dead()?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      2. 深度题
        1. 1. 为何项目里除了 System.Action 还会用到 UnityAction?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 与美术约定导出模型时,你会强调哪两条「硬规则」?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. 打开设置把 Time.timeScale 设为 0,关面板时哪些路径必须把缩放设回 1?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. 同名的 SettingPanel 放到 BeginScene 与 GameScene,单例会冲突吗?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        5. 5. 小地图相机为何常用 LateUpdate 跟随,且要关掉 Audio Listener?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        6. 6. WinPanel 点确定时先 timeScale = 1 再 LoadScene,必要性在哪?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        7. 7. Development Build 与正式发包选项如何取舍?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章

32.总结


32.1 知识点

学习的主要内容

总结目的

Unity做游戏的套路


如何学好Unity



达到目的

练习


32.2 核心要点速览

场景切换与退出

要点 说明
入口 SceneManager.LoadScene(场景名或 Build 索引)using UnityEngine.SceneManagement;
常见坑 场景未加入 Build Settings 列表则运行态切换失败
旧 API Application.LoadLevel 已弃用,新代码统一 SceneManager
退出 Application.Quit() 仅在已发布包体生效,编辑器 Play 无效
SceneManager.LoadScene("场景2");
Application.Quit();

鼠标光标与 Cursor API

API / 成员 作用 注意
Cursor.visible 是否显示硬件指针 false 在 Game 视图内隐藏
Cursor.lockState None / Locked / Confined Locked 常配合视角锁定;编辑器 Esc 可解除
Cursor.SetCursor 自定义纹理与热点 热点相对贴图左上角;第三参 CursorMode

随机数与委托

**C# Random**:Next(min, max) 左闭右开

**Unity Random.Range**:

重载 区间
int 左闭右开,如 Random.Range(0, 100) → 0~99
float 双闭区间

委托Action / Func 与命名空间 UnityEngine.Events 下的 UnityAction —— 常配合 UnityEvent、Inspector 绑定,语义接近无参 Action

模型资源导入

要点
构成 网格 — 形,必须;贴图 — 色,必须;骨骼 — 有动画才要
格式 首选 FBX;亦支持 .dae.3ds.dxf.obj
对接美术 前向对齐模型空间 +Z单位与缩放与工程一致
素材来源 Asset Store、成套资源包等

坦克迷宫:项目概述与需求

类型:俯视角坦克迷宫;拆解方式:按 OOP 把需求划到 UI、存档、核心玩法三条线,再落到脚本与数据类。

前置知识

内容
Unity 基础 场景、物体、组件、预制体
持久化 PlayerPrefs + 封装管理器做序列化读写
GUI 自定义 CustomGUI 控件与事件委托

功能需求

线 内容
UI 8 脚本1 个面板基类,管显隐与单例;7 个面板 — 开始、设置、排行榜、游戏 HUD、胜利、失败、退出确认等;按钮监听里切场景或叠面板;防穿透:先藏当前面板再显目标
存档 音效:BGM/SFX 开关与音量;排行榜:玩家名、分数、通关时间;统一由 数据管理单例 持有 MusicDataRankList,改完即 Save
核心玩法 坦克基类 → 玩家坦克 / 移动敌坦 / 固定炮塔;武器与子弹可摧毁箱子属性或武器奖励小地图相机跟目标——与 UI、存档并行实现

实现主线

  1. 工程:导入 CustomGUIPlayerPrefsDataMgrTDSTK.unitypackage,用预制体搭 BeginScene / GameScene 展示场景与关卡围合。
  2. UI 骨架BasePanel<T> + 开始/设置/排行榜等;开始场景 CursorLockMode.Confined 限制指针在窗口内。
  3. 设置与音效数据MusicData + GameDataMgr 构造里 Load,首次用 notFirst 写默认「全开、音量满」再 Save;设置面板 Show 时刷新控件、**Hide 时 timeScale = 1**。
  4. 排行榜RankInfo / RankListAdd 后按 通关时间升序 排序、只留前 10 条;面板用 Find("父/子名") 路径 批量取标签,Show 时把秒数格式化成 时/分/秒 字符串。
  5. BGMBKMusic 单例 + AudioSourcevolume / muteGameDataMgr 同步。
  6. 游戏 HUDGamePaneldeltaTime 累加计时、改血条 宽度比例;打开设置或退出确认时 Time.timeScale = 0设置 / 退出面板 Hide 里恢复 timeScale = 1设置 复制到游戏场景后,每场景各一份单例,靠 **Awake 重绑 Instance**。

工程依赖包

作用
CustomGUI.unitypackage 按钮、滑条、标签等封装与点击/值变更事件
PlayerPrefsDataMgr.unitypackage 反射 把自定义类型读写进 PlayerPrefs
TDSTK.unitypackage 坦克迷宫相关模型、预制体等

开始场景装饰

思路:双场景建好 → 预制体铺 地板、墙、展示坦克 → 摄像机当菜单背景 → 定向光 氛围 → 装饰物挂 慢速绕 Y 轴旋转

void Update()
{
    transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
}

面板基类与开始 / 设置

BasePanel<T> 要点

做法
约束 where T : classAwakeinstance = this as T
显隐 SetActive(true/false)
注意 同场景 同脚本只挂一处,否则静态单例被覆盖

开始面板:开始游戏 → LoadScene("GameScene");设置/排行榜 → 目标 **ShowMe + 自己 HideMe**;退出 → Application.Quit()

设置面板:初始 HideMe;关面板时若当前是 BeginSceneBeginPanel.ShowMe();滑条/开关 +=GameDataMgrShowMeUpdatePanelInfo() 同步磁盘数据到控件。

// 典型:打开子面板并防穿透
SettingPanel.Instance.ShowMe();
HideMe();

音效数据与 GameDataMgr

MusicData 字段isOpenBKisOpenSoundbkValuesoundValuenotFirst

构造里首次进入

musicData = PlayerPrefsDataMgr.Instance.LoadData(typeof(MusicData), "Music") as MusicData;
if (!musicData.notFirst)
{
    musicData.notFirst = true;
    musicData.isOpenBK = musicData.isOpenSound = true;
    musicData.bkValue = musicData.soundValue = 1f;
    PlayerPrefsDataMgr.Instance.SaveData(musicData, "Music");
}

对外方法:改音量/开关 → 写回 musicDataSaveData;BGM 实际听感由 BKMusicAudioSource

排行榜数据与面板

类型 作用
RankInfo namescoretime无参构造 方便序列化
RankList List<RankInfo>

AddRankInfo 流程AddSort时间短者靠前 → 从尾部删到 只保留 10 条SaveData

面板刷新:循环 Find("Name/labName" + i)CustomGUILabelShowMeUpdatePanelInfo,秒内整数拆 时 / 分 / 秒 拼字符串 — 除法拆段与 HUD 计时相同

背景音乐 BKMusic

方法 作用
ChangeValue(float) audioSource.volume = value
ChangeOpen(bool) audioSource.mute = !isOpen

Awake:单例、GetComponent<AudioSource>(),用 GameDataMgr.Instance.musicData 做一次初始化同步。

游戏场景:地形、HUD、暂停

地形:地板 + 四面围墙 预制体拼出可玩区域。

GamePanel

职责 做法
分数 外部调 AddScore,改 labScore 文本
时间 nowTime += Time.deltaTime,整数秒后格式化为 时/分/秒
血条 texHP.guiPos.width = (float)HP / maxHP * hpW
暂停 点设置或退出确认 → Time.timeScale = 0

跨场景的设置面板:进新场景 重新 AwakeSettingPanel.Instance 永远指向 当前场景 里那一个;**HideMe 统一 timeScale = 1**,Begin 场景关设置时再多一步 显示开始面板

QuitPanel:确认 → LoadScene("BeginScene");继续/关窗 → HideMe(),且在 **HideMe 末尾 timeScale = 1**。

坦克基类 TankBaseObj

成员 / 方法 作用
atk def maxHp hp 攻防与血量
tankHead 炮台 Transform,供子类旋转瞄准
moveSpeed roundSpeed headRoundSpeed 移动与旋转参数
deadEff 死亡时 Instantiate 的特效预制体
abstract void Fire() 子类实现具体开火
virtual Wound(TankBaseObj other) dmg = other.atk - defdmg <= 0 不扣血;hp <= 0Dead
virtual Dead() Destroy(gameObject);有特效则实例化并按 GameDataMgr.musicDataAudioSource 音量与 mute 后 Play

玩家坦克 PlayerObj

做法
移动 Translate 竖轴、Rotate 横轴;炮台跟 Mouse X
开火 GetMouseButtonDown(0)Fire()nowWeapon.Fire()
受伤 override WoundbaseGamePanel.Instance.UpdateHP(maxHp, hp)
死亡 不调用 base.Dead(),避免销毁带主摄像机的物体;timeScale = 0LosePanel.ShowMe()
换武器 销毁旧 WeaponObj,在 weaponPos Instantiate(..., false),取 WeaponObjSetFather(this)

摄像机:主相机挂在 炮台 子级,转炮台即转视角。

小地图摄像机

步骤 要点
专用相机 去掉 Audio Listener,避免双监听器
RenderTexture 建 RT,赋给相机 Target Texture
UI 将 RT 赋给 HUD 上的小地图图控件
俯视 相机拉高、俯视场景
跟随 CameraMoveLateUpdateposition.x/z 跟玩家,y = H 常量

武器与子弹

WeaponObjbullet 预制体、shootPos[]fatherObjFire 循环实例化子弹并 BulletObj.SetFather

BulletObjUpdate 沿自身 forward 移动;触发器 OnTriggerEnterTagCube,或 Player/Monster 与发射方阵营交叉 时,对 TankBaseObjWound(fatherObj),生成爆炸特效并按全局音效数据播声音,**Destroy 自身**。

工程注意
玩家坦克 Rigidbody 建议 冻结旋转、锁定 Y,避免与场景体碰撞产生翻转

武器奖励与自动销毁

WeaponReward:触发 PlayerRandom.Range 选武器预制体 → PlayerObj.ChangeWeapon → 实例化 getEff 音效 → Destroy 自身

AutoDestroyStartDestroy(gameObject, time),用于子弹、特效寿命。

属性奖励 PropReward

要点
E_PropType Atk / Def / MaxHp / Hp
触发 Player 进入触发器,switchPlayerObj 对应字段
血条 MaxHpHp 变化后 GamePanel.UpdateHP;当前血 封顶 maxHp
收尾 播放获取特效、Destroy 自身

可击毁箱子 CubeObj

流程 要点
概率 Random.Range(0,100) < 50 时在原位 Instantiate 奖励预制体数组中随机一项
表现 实例化 deadEff,按全局音效设置播声
收尾 Destroy 自身

课内 CubeObj 全码在触发进入时即执行上述逻辑;正式项目宜再用 Tag / Layer 限定触发源,避免误触。

固定炮塔 MonsterTower

做法
炮台旋转 子物体挂旋转脚本,本类只管开火节奏
开火 Update 累加 nowTime,超 fireOffsetTimeFire,置零计时
Fire 多发射点 Instantiate 子弹并 SetFather(this)
免伤 override Wound 空实现,不扣血不死亡

移动敌人 MonsterObj

做法
巡逻 RandomPosrandomPos[] 取目标;LookAt + Translate forward;距目标 小于 0.05 再换点
瞄准 tankHead.LookAt(lookAtTarget),一般绑玩家
近战开火 与目标距离 ≤ fireDis 时按 fireOffsetTime 间隔 Fire
死亡 base.Dead()GamePanel.AddScore(10)
血条 OnGUIshowTime > 0 时递减;WorldToScreenPointy = Screen.height - y 转 GUI 坐标;GUI.DrawTexture 底条 + 按 hp/maxHp 缩宽血条;**WoundshowTime = 3**

通关与胜败界面

EndPointPlayer 进入触发器 → timeScale = 0WinPanel.ShowMe()

WinPanel:初始 HideMe;确定:timeScale = 1AddRankInfo(昵称, GamePanel.nowScore, GamePanel.nowTime)LoadScene("BeginScene")

LosePanel:回菜单 → BeginScene;再来一局 → LoadScene("GameScene") 重载整关;两按钮均先 timeScale = 1

失败流程在 PlayerObj.Dead 里与胜利对称:**暂停 + LosePanel.ShowMe()**。

构建与 Player 设置

Build Settings

含义摘要
Target Platform Windows / macOS / Linux 等
Architecture x86 / x86_64 等,视目标 CPU
Development Build 开发包,可开 Profiler、脚本调试等子项
Compression Default / LZ4 / LZ4HC,权衡包体与解压速度

Player SettingsCompany / Product NameVersion、默认 Icon / CursorResolutionFullscreen Mode、默认宽高、Run In background 等。

产出:参数设好 → Build,选输出目录生成可执行包。


32.3 面试题精选

进阶题

1. SceneManager.LoadScene 运行时失败常见原因?

题目

代码里调用 LoadScene 抛错或进不了目标场景,你会先查哪几项?

深入解析
  • 目标场景是否已加入 Build Settings 列表、名称/索引是否与代码一致。
  • 是否缺少 using UnityEngine.SceneManagement;
  • 单例/加载流程是否在合法时机调用(如同一帧多次加载需留意异步 API 等,入门篇以同步 LoadScene 为主)。
答题示例

先看 Build Settings 里有没有该场景、名字写没写对,再看命名空间和调用时机。

参考文章
  • 1.必备知识点-场景切换和游戏退出

2. CursorLockMode.LockedConfined 各解决什么问题?

题目

第一人称视角常用哪种锁鼠标?只想把指针限制在 Game 窗口内用哪种?

深入解析
  • Locked:指针锁到视图中心并通常隐藏,适合 FPS 视角控制;编辑器下 Esc 可解除。
  • Confined:指针限制在窗口内,不强制居中隐藏,适合不需要「中心锁定」的窗口内操作。
答题示例

FPS 用 Locked;只要不出窗口用 Confined。

参考文章
  • 2.必备知识点-鼠标隐藏锁定相关

3. Random.Range 的 int 与 float 重载在区间边界上有何不同?

题目

同一方法名,为何 int 与 float 版本「含不含上界」不一样?

深入解析
  • int:上界不包含(离散整数惯例)。
  • float双闭区间(连续浮点插值)。
  • System.Random.Next 的左闭右开需对比记忆,避免 off-by-one。
答题示例

int 版上界取不到;float 版上下界都能取到。

参考文章
  • 3.必备知识点-随机数和Unity自带委托相关

4. BasePanel<T> 为何要 where T : class,单例在 Awake 里怎么拿到具体面板类型?

题目

泛型面板基类里 instance = this as T 的前提是什么?为何不用 new 做单例?

深入解析
  • where T : classthis as T 要求 T 为引用类型,否则值类型与 as 规则不兼容。
  • MonoBehaviour:由引擎在场景里挂载实例化,**禁止 new**;在 Awake(该物体已存在、脚本唯一)里把 当前实例 赋给静态 instanceT 为各面板子类如 BeginPanel
  • 代价:每场景若重复放两份同脚本会互相覆盖 Instance,工程上保证 每场景每面板脚本只挂一处
答题示例

T 要约束成引用类型才能 as 成具体面板;Mono 不能 new,Awake 里把自己赋给静态单例。

参考文章
  • 8.开始场景-开始界面

5. RankPanel 里用 transform.Find("Name/labName" + i) 取控件,路径里斜杠表示什么?

题目

为何不直接 Find("labName1")Find 默认能搜多深?

深入解析
  • /:表示 父子层级,即从当前 transform 的下一层 Name 再找到 labName1;等价于多级子节点路径。
  • **默认 Find**:一般只找 直接子物体(Unity 版本行为以文档为准);跨层时常用 路径字符串 或改在父节点上 Find
  • 工程取舍:控件多时用循环 + 约定命名 减少 Inspector 拖拽
答题示例

斜杠是父子路径,从 Name 子物体下取 labName1;比每层单独 Find 省事。

参考文章
  • 11.开始场景-排行榜界面

6. GameDataMgr 构造里为何用 notFirst 判断并写回默认音量?

题目

第一次装游戏时 LoadData 可能得到什么?为何要立刻 SaveData

深入解析
  • 反序列化/首次无键时,布尔与数值可能是 默认 false / 0,不符合「默认音乐音效全开」的产品预期。
  • notFirst 为 false 视为首次:拉满音量、开开关,标 notFirst = true持久化,下次启动走正常读取。
  • PlayerPrefsDataMgr反射存取 配套,保证 内存模型与磁盘一致
答题示例

首次存档可能是全关静音,用 notFirst 识别后设成默认全开并 Save,以后就读用户设的了。

参考文章
  • 10.开始场景-音效数据逻辑

7. TankBaseObj.Wounddmg = atk - defdmg <= 0 时为何直接 return?

题目

想表达什么设计?若允许 0 伤仍要触发受击表现该怎么扩展?

深入解析
  • 不破防:防御不低于对方攻击时不扣血,避免负数伤害或无效结算。
  • 若要做「格挡特效」等,可与血量分支分离,在 dmg <= 0 时另调表现而不改 hp
答题示例

攻击减防御小于等于 0 就不造成伤害;要受击反馈可以单独做特效分支。

参考文章
  • 18.游戏场景-坦克基类

8. 子弹 OnTriggerEnter 如何用 Player / Monster Tag 做阵营过滤?

题目

为何用 fatherObj.CompareTagother.CompareTag 组合判断?

深入解析
  • Cube 作为场景可破坏体,双方子弹都可引爆。
  • 玩家子弹只应伤 Monster怪子弹只应伤 Player:用 other 是谁fatherObj 是谁发射 交叉判断,避免自伤或同阵营互打。
答题示例

看被撞的是 Player 还是 Monster,再和发射方 Tag 交叉判断,Cube 单独一条。

参考文章
  • 21.玩家-武器对象和子弹对象
  • 25.敌人-固定不动的敌人

9. PlayerObj 重写 Dead 时为何不调用 base.Dead()

题目

主摄像机挂在玩家子层级时,直接 Destroy 玩家会怎样?

深入解析
  • base.DeadDestroy 整个玩家物体,子物体主相机一并销毁,场景失去渲染与后续 UI 逻辑载体。
  • 课内改为 暂停 + 失败面板,保留场景结构,由 LosePanel 再决定回菜单或重载关卡。
答题示例

父类会 Destroy 自己,相机跟着没了;所以玩家死亡只暂停并弹失败 UI。

参考文章
  • 19.玩家-基础移动旋转摄像机跟随等
  • 30.失败界面

深度题

1. 为何项目里除了 System.Action 还会用到 UnityAction

题目

二者都能表示无返回委托,Unity 工程里何时更偏向 UnityAction

深入解析
  • UnityAction 位于 UnityEngine.Events,与 UnityEvent、Inspector 持久化、UI Button 的 onClick 等管线一致,序列化与编辑器绑定更顺。
  • Action/Func 是纯 .NET,在任意 C# 逻辑中通用;与 Unity 可视化事件绑定时用 UnityAction 更贴合工具链。
答题示例

要跟 UnityEvent、UI 或 Inspector 里拖方法衔接时用 UnityAction;纯代码里 Action 一样写。

参考文章
  • 3.必备知识点-随机数和Unity自带委托相关

2. 与美术约定导出模型时,你会强调哪两条「硬规则」?

题目

结合本课导图,口述对接 3D 资源时最容易踩坑的两点。

深入解析
  • 朝向:模型前向对齐 +Z(与 Unity 常用前向一致),减少后续逻辑里额外旋转补偿。
  • 单位与缩放:DCC 与 Unity 单位统一(米/厘米等),避免导入后整体缩放错误连带物理、动画比例问题。
  • 格式上优先 FBX,减少非主流格式带来的法线、材质拆分问题。
答题示例

前向朝 Z、单位缩放统一,再加一句优先 FBX。

参考文章
  • 4.必备知识点-模型资源的导入

3. 打开设置把 Time.timeScale 设为 0,关面板时哪些路径必须把缩放设回 1?

题目

SettingPanel.HideMeQuitPanel.HideMe 都做了什么事?漏一处会怎样?

深入解析
  • GamePanel 打开设置或退出确认时 Time.timeScale = 0 暂停 Update/FixedUpdate(除不受缩放影响的少数系统)
  • SettingPanel.HideMe 重写里 Time.timeScale = 1,开始场景下关设置还会 BeginPanel.ShowMe();游戏场景关设置同样走 HideMe,时间缩放会恢复。
  • QuitPanel.HideMe 末尾也 timeScale = 1,用于从「退出确认」返回游戏。若某条分支只 SetActive(false)走上述 HideMe,才可能卡在暂停态。
答题示例

暂停靠 timeScale=0,继续玩必须在关设置或关退出面板时设回 1,否则 Update 全停。

参考文章
  • 9.开始场景-设置界面
  • 15.游戏场景-游戏主界面
  • 17.游戏场景-游戏退出界面

4. 同名的 SettingPanel 放到 BeginScene 与 GameScene,单例会冲突吗?

题目

两个场景各有一份设置面板预制体时,Instance 指向谁?

深入解析
  • 静态 Instance 跟进程走:进入某场景、该场景里 SettingPanelAwake 执行instance 被设为 当前场景那一颗
  • 切场景:旧场景卸载后旧实例销毁,新场景 **Awake 再赋新 Instance**,因此 不会两个场景共用一个物体,但 代码写的必须是「当前场景那一份」
  • 注意:DontDestroyOnLoad 若误用会把旧实例带去新场景,与本课「复制预制到另一场景」的教法不同,需区分。
答题示例

不冲突,谁 Awake 谁就是当前 Instance;切场景会换新的。别和 DontDestroy 混用搞混。

参考文章
  • 16.游戏场景-游戏设置界面

5. 小地图相机为何常用 LateUpdate 跟随,且要关掉 Audio Listener?

题目

和主相机同帧跟随时容易出现什么问题?双 Listener 会怎样?

深入解析
  • LateUpdate:在玩家 Update 位移之后再抄位置,减少一帧抖动或不同步。
  • 仅一个 Audio Listener:多 Listener 行为未定义 / 报错风险,辅机位只出画面不参与收听。
答题示例

晚一阶段跟玩家位置更稳;副相机不要第二个 Listener。

参考文章
  • 20.玩家-小地图制作

6. WinPanel 点确定时先 timeScale = 1LoadScene,必要性在哪?

题目

若保持 0 直接切场景会有何隐患?

深入解析
  • 部分流程在时间缩放为 0Update 不推进,与排行榜写入、输入收尾等组合时易出现状态不一致或体感卡顿;先恢复 1 再切场景更干净。
  • BeginScene 后本场景卸载,但显式恢复仍是好习惯,与设置/退出面板写法一致。
答题示例

先恢复时间流速再切场景,避免暂停态残留影响逻辑。

参考文章
  • 29.胜利界面

7. Development Build 与正式发包选项如何取舍?

题目

给测试同学的包和给玩家的包应差在哪几项?

深入解析
  • Development Build:开 Profiler 连接、脚本调试、Deep Profiling 等,包体更大、性能更差,适合内测定位问题。
  • 正式包:关 Development,按需选 LZ4 / LZ4HC 压缩;Player Settings 里产品名、版本、图标、全屏策略与 Run in background 按发行平台调整。
答题示例

内测开 Development 方便连 Profiler;上架包关掉,压缩用 LZ4 系,Player 里把产品信息和分辨率模式配好。

参考文章
  • 31.项目打包


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏