Skip to content

游戏客户端基础 共100题

说明:

  • Unity 生命周期、协程、对象池、资源加载、UGUI、性能优化、同步方式等题点。

题型统计

题型数量
单选题35
多选题20
判断题10
填空题10
代码阅读题10
代码填空题5
简答题7
场景分析题3
合计100

一、单选题

1. Unity 中 GameObject 和 Component 的关系,下列说法正确的是?

A. GameObject 本身承载场景对象,具体行为主要由 Component 提供
B. Component 可以脱离 GameObject 单独存在于场景中
C. Transform 不是 Component
D. GameObject 只能挂一个 Component

答案:A

解析:GameObject 是场景对象的容器,Transform、Renderer、Collider、脚本等都属于组件。


2. 同一个激活对象第一次进入场景时,常见生命周期顺序是?

A. Start -> Awake -> OnEnable
B. Awake -> OnEnable -> Start
C. OnEnable -> Start -> Awake
D. Update -> Start -> Awake

答案:B

解析:Awake 用于初始化,OnEnable 在对象启用时调用,Start 在第一次 Update 前调用。

题目图示


3. Awake 更适合放哪类逻辑?

A. 初始化自身字段和缓存组件引用
B. 每帧移动角色
C. 固定频率物理模拟
D. UI 点击回调里的业务提交

答案:A

解析:Awake 通常用于自身初始化,依赖其他对象启动顺序的逻辑要谨慎。


4. Start 的调用特点是?

A. 每帧都会调用
B. 对象启用后,在第一次 Update 前调用一次
C. 只在编辑器里调用
D. 只在物理帧调用

答案:B

解析:Start 不是每次启用都重复执行,一般作为首次启动逻辑。


5. FixedUpdate 通常用于?

A. 物理相关更新
B. UI 排版
C. 资源打包
D. 网络 DNS 解析

答案:A

解析:FixedUpdate 按固定游戏时间间隔执行,适合 Rigidbody 相关逻辑。


6. LateUpdate 常见用途是?

A. 在角色 Update 后处理相机跟随
B. 打包 AssetBundle
C. 加载配置表
D. 执行静态构造函数

答案:A

解析:相机跟随放在 LateUpdate 可以减少跟随目标先后顺序造成的抖动。


7. 实现帧率无关移动通常使用?

A. Time.deltaTime
B. Time.frameCount
C. Application.version
D. Screen.width

答案:A

解析:速度乘以 deltaTime 可以让单位时间位移更稳定。

题目图示


8. 当 Time.timeScale 设置为 0 时,Time.deltaTime 通常会?

A. 变为 0
B. 变为 1
C. 不受影响
D. 变成负数

答案:A

解析:deltaTime 会受 timeScale 缩放,暂停时通常为 0。


9. 暂停界面倒计时仍希望按真实时间走,应优先使用?

A. Time.unscaledDeltaTime
B. Time.deltaTime
C. Time.fixedTime
D. Time.time

答案:A

解析:unscaledDeltaTime 不受 timeScale 影响,适合暂停界面、真实时间动画。


10. 父物体 SetActive(false) 后,子物体的 activeSelf 与 activeInHierarchy 通常如何?

A. 子物体 activeSelf 可能仍为 true,但 activeInHierarchy 为 false
B. 二者一定都为 true
C. 二者一定都为 false
D. activeInHierarchy 不受父物体影响

答案:A

解析:activeSelf 表示自身开关,activeInHierarchy 表示层级中最终是否激活。


11. activeInHierarchy 表示?

A. 对象在层级中最终是否处于激活状态
B. 对象自身 Inspector 勾选状态
C. 对象是否有 Rigidbody
D. 对象是否是 Prefab

答案:A

解析:父节点关闭会让子节点 activeInHierarchy 为 false。


12. Unity 协程方法常见返回类型是?

A. IEnumerator
B. Thread
C. Task<int>
D. Action

答案:A

解析:协程通过 IEnumerator/yield 将执行切分到多帧。


13. 关于 Unity 协程,下列说法正确的是?

A. 协程默认仍在主线程上分段执行
B. StartCoroutine 一定创建新线程
C. 协程一定比 Update 快
D. 协程不能访问 Unity API

答案:A

解析:协程不是线程,适合拆分等待流程,但 CPU 重活仍会阻塞主线程。


14. 将 MonoBehaviour.enabled 设置为 false,对该脚本已启动的协程通常会怎样?

A. 不会因为 enabled=false 自动停止
B. 一定立即停止
C. 一定切到后台线程
D. 一定重新从头开始

答案:A

解析:禁用组件本身不会自动停止协程;关闭 GameObject 或销毁对象则会影响协程。


15. GameObject SetActive(false) 对挂在其上的协程通常会怎样?

A. 会停止该对象上的协程
B. 完全没有影响
C. 只影响 FixedUpdate 不影响协程
D. 只在编辑器停止

答案:A

解析:关闭 GameObject 会停止附着在它上面的协程。


16. 对象池最主要减少的是?

A. 频繁 Instantiate/Destroy 带来的分配和回收开销
B. 所有算法复杂度
C. 网络协议数量
D. 源代码行数

答案:A

解析:对象池复用短生命周期对象,减少 CPU 与 GC 压力。

题目图示


17. 大量子弹每帧创建销毁,最可能造成?

A. GC/CPU 抖动和内存碎片
B. 纹理自动压缩
C. 帧率一定提升
D. 服务器延迟归零

答案:A

解析:频繁分配和销毁会带来管理成本,移动端尤其容易出现卡顿。


18. Resources.Load 的资源通常需要放在?

A. 名为 Resources 的目录下
B. 任意 Editor 目录下
C. StreamingAssets 之外任意位置都行
D. Library 目录下

答案:A

解析:Resources API 按 Resources 目录下的路径加载,不写文件扩展名。


19. AssetBundle 的基本作用是?

A. 把非代码资源打成运行时可加载的资源包
B. 替代所有 C# 代码
C. 只用于保存 PlayerPrefs
D. 只用于网络握手

答案:A

解析:AssetBundle 常用于 DLC、热更资源、减小首包、平台资源拆分。


20. Addressables 相比手写 AssetBundle 管理,主要优势是?

A. 通过地址加载并管理依赖和引用计数
B. 让所有资源永远不占内存
C. 让代码自动热更新
D. 让所有平台包通用

答案:A

解析:Addressables 封装了地址、依赖、异步加载和释放流程。

题目图示


21. Addressables 显式加载资源后,用完通常需要?

A. Release 对应句柄或资源
B. Delete ProjectSettings
C. 调用 GC.Collect 就够了
D. 重新启动编辑器

答案:A

解析:引用计数归零后,系统才有机会卸载相关资源。


22. DestroyImmediate 更推荐用于?

A. 编辑器工具中的立即销毁
B. 普通运行时每帧销毁对象
C. 网络收包
D. 播放动画

答案:A

解析:运行时通常使用 Destroy,DestroyImmediate 容易破坏运行时对象生命周期。


23. Transform.position 表示?

A. 世界坐标
B. 局部坐标
C. 屏幕像素坐标
D. 纹理 UV 坐标

答案:A

解析:localPosition 才是相对父节点的局部坐标。


24. Prefab 的主要意义是?

A. 复用一套对象层级和组件配置
B. 只保存脚本源码
C. 只保存运行日志
D. 替代场景文件

答案:A

解析:Prefab 适合复用角色、UI、特效、子弹等对象模板。


25. Rigidbody 物体的物理移动更推荐放在?

A. FixedUpdate 中配合 Rigidbody API
B. OnGUI
C. 静态构造函数
D. 资源导入回调

答案:A

解析:物理系统按固定步长模拟,直接改 Transform 可能绕开物理求解。


26. 3D 碰撞回调 OnCollisionEnter 一般要求?

A. 双方有 Collider,且至少一方有 Rigidbody
B. 双方都必须没有 Collider
C. 只要有 MeshRenderer
D. 只要对象名字相同

答案:A

解析:碰撞检测依赖 Collider/Rigidbody 组合。


27. Trigger 触发器常见要求是?

A. Collider 勾选 Is Trigger,且至少一方有 Rigidbody
B. 必须没有 Rigidbody
C. 只能用于 UI
D. 必须放在 Resources 下

答案:A

解析:Trigger 不做刚体碰撞响应,但会产生触发回调。


28. 频繁改变同一大 Canvas 下的 UI,可能导致?

A. Canvas rebuild 开销增加
B. 磁盘空间减少
C. DNS 查询变慢
D. 脚本无法编译

答案:A

解析:动态 UI 与静态 UI 混在一个 Canvas 中,容易扩大重建范围。


29. UGUI 中不需要响应点击的 Image/Text,通常可以关闭?

A. Raycast Target
B. Transform
C. GameObject 名称
D. CanvasScaler

答案:A

解析:关闭无用 Raycast Target 可以减少射线检测候选。


30. 长列表 ScrollRect 的常见优化是?

A. 只创建可见范围附近的 item 并复用
B. 一次生成所有 item
C. 每帧重建所有布局
D. 给每个 item 加一个独立相机

答案:A

解析:虚拟列表/循环列表能显著减少对象数和布局开销。


31. Animator Controller 中常用来驱动状态切换的是?

A. 参数和 Transition
B. DNS 记录
C. 端口号
D. 纹理 mipmap

答案:A

解析:Animator 通过状态机、参数、过渡条件控制动画流转。


32. Particle System 的 Simulation Space 主要决定?

A. 粒子按本地空间还是世界空间模拟
B. C# 是否装箱
C. 网络是否重传
D. 是否生成 AssetBundle

答案:A

解析:Local/World 会影响父节点移动缩放时粒子的表现。


33. C# 中 class 与 struct 的核心区别之一是?

A. class 是引用类型,struct 是值类型
B. class 一定在栈上,struct 一定在堆上
C. struct 可以继承任意类
D. 二者完全相同

答案:A

解析:值类型复制值,引用类型复制引用。


34. 事件订阅后不取消,常见风险是?

A. 对象被事件源持有导致无法释放或回调到失效对象
B. 代码自动变快
C. 资源自动打包
D. 协程自动停止

答案:A

解析:事件源生命周期更长时,订阅者可能被间接持有。


35. 定位 Unity 客户端卡顿,首先应该使用哪类工具?

A. Profiler/Frame Debugger/Memory Profiler 等分析工具
B. 随机删除代码
C. 只看 FPS 数字
D. 只改美术资源名字

答案:A

解析:优化前先定位瓶颈,区分 CPU、GPU、GC、IO、网络等问题。


二、多选题

1. 以下属于 Unity 常见生命周期函数的有?

A. Awake
B. OnEnable
C. Start
D. Update

答案:A、B、C、D

解析:四个都是 MonoBehaviour 常见生命周期函数。


2. 关于 Update、FixedUpdate、LateUpdate,下列正确的有?

A. Update 每帧调用
B. FixedUpdate 按固定游戏时间间隔调用
C. LateUpdate 在 Update 后调用
D. FixedUpdate 一定每渲染帧只调用一次

答案:A、B、C

解析:帧率波动时,一个渲染帧内可能没有 FixedUpdate,也可能有多个。


3. 对象池适合复用哪些对象?

A. 子弹
B. 飘字
C. 短生命周期特效
D. 永远只有一个的配置表

答案:A、B、C

解析:高频创建销毁对象适合池化,唯一配置表通常不需要对象池。

题目图示


4. 对象从池中取出前,通常需要重置哪些状态?

A. 位置/旋转/缩放
B. 生命周期计时
C. 特效播放状态
D. 上一次绑定的事件或目标引用

答案:A、B、C、D

解析:池化对象最大风险是脏状态复用。


5. 资源管理中容易导致内存问题的做法有?

A. 重复加载同一资源
B. 引用计数没有释放
C. 切场景前不处理常驻对象
D. 加载后永远不卸载临时资源

答案:A、B、C、D

解析:资源生命周期不清晰会导致重复占用和峰值内存过高。


6. 使用 Addressables 时,较合理的做法有?

A. 异步加载
B. 保存并释放 handle
C. 按场景或系统规划 group
D. 加载完后完全不释放

答案:A、B、C

解析:不释放 handle 会让引用计数长期不归零。


7. Unity C# 中常见隐藏 GC 来源有?

A. 频繁 new 临时对象
B. 装箱
C. 闭包捕获
D. 每帧字符串拼接

答案:A、B、C、D

解析:这些都会产生托管堆分配或额外对象。


8. UGUI 常见优化方式有?

A. 动静分离 Canvas
B. 关闭无用 Raycast Target
C. ScrollRect item 复用
D. 避免频繁触发布局重建

答案:A、B、C、D

解析:UI 优化核心是减少重建、射线检测和过量对象。

题目图示


9. 降低 DrawCall/渲染开销的常见方式有?

A. 合批/图集
B. 减少材质切换
C. GPU Instancing
D. 给每个物体单独材质实例

答案:A、B、C

解析:单独材质实例通常会破坏批处理。


10. 数据驱动配置的好处有?

A. 减少硬编码
B. 方便策划调参
C. 支持热更新配置
D. 让所有 Bug 自动消失

答案:A、B、C

解析:数据驱动提高迭代效率,但不能替代测试和约束。


11. 有限状态机 FSM 通常包含?

A. 状态
B. 状态切换条件
C. 进入/退出逻辑
D. 状态更新逻辑

答案:A、B、C、D

解析:FSM 常用于角色、AI、技能、UI 流程。


12. 游戏网络同步中常见技术有?

A. 客户端预测
B. 服务器校正
C. 插值平滑
D. 每帧阻塞等待服务器

答案:A、B、C

解析:阻塞等待会严重损害操作手感。

题目图示


13. 实现帧率无关移动时,需要注意?

A. 速度乘 deltaTime
B. 避免把 deltaTime 重复乘两次
C. 暂停时区分 scaled/unscaled 时间
D. 物理对象尽量配合 FixedUpdate

答案:A、B、C、D

解析:时间来源和更新阶段要匹配。


14. 移动端适配常见内容包括?

A. 安全区
B. 分辨率与宽高比
C. 字体与本地化长度
D. 触控区域

答案:A、B、C、D

解析:游戏 UI 要兼顾刘海屏、平板、不同语言和可点击性。


15. 热更新/动态更新中,通常可以更新的内容有?

A. 配置表
B. AssetBundle/Addressables 资源
C. Lua/脚本热修逻辑
D. 客户端权限外的系统库

答案:A、B、C

解析:底层系统库和平台受限内容不能随意动态替换。


16. 切场景时需要考虑?

A. 异步加载进度
B. 旧场景资源释放
C. 常驻管理器是否重复创建
D. 峰值内存

答案:A、B、C、D

解析:场景切换是加载、卸载和常驻对象管理的集中点。


17. 输入系统处理中常见注意点有?

A. 点击穿透
B. 多点触控
C. UI 与场景点击优先级
D. 不同平台输入差异

答案:A、B、C、D

解析:输入要同时考虑 UI、场景和设备差异。


18. 客户端日志系统通常需要记录?

A. 关键错误
B. 资源加载失败
C. 网络断线/重连
D. 重要状态切换

答案:A、B、C、D

解析:日志要能帮助复现和定位线上问题。


19. 异步加载界面应关注?

A. 进度反馈
B. 错误兜底
C. 取消或超时处理
D. 加载完成后的引用管理

答案:A、B、C、D

解析:加载流程要处理失败和退出,不只是显示进度条。


20. 低端机性能分级常见策略有?

A. 降低特效等级
B. 降低阴影/后处理
C. 限制同屏对象数量
D. 强制开启最高画质

答案:A、B、C

解析:分级策略要按设备能力提供可接受体验。


三、判断题

1. Awake 一定在 Start 之前调用。

答案:对

解析:同一脚本生命周期中 Awake 早于 Start。


2. 禁用 MonoBehaviour.enabled 一定会停止该脚本已启动的协程。

答案:错

解析:enabled=false 不会自动停止协程。


3. 父物体关闭后,子物体 activeInHierarchy 会受到影响。

答案:对

解析:层级最终激活状态取决于父链路。


4. Time.deltaTime 表示上一帧到当前帧的时间间隔,并受 timeScale 影响。

答案:对

解析:暂停时 deltaTime 通常变为 0。


5. FixedUpdate 在每个渲染帧中一定只执行一次。

答案:错

解析:可能 0 次,也可能多次。


6. 对象池一定提升性能,没有任何副作用。

答案:错

解析:对象池可能带来脏状态、常驻内存、池大小策略等问题。


7. Resources 目录适合无限制放入所有项目资源。

答案:错

解析:大量使用 Resources 会增加管理和内存风险。


8. Addressables 引用计数归零后,相关资源才有机会卸载。

答案:对

解析:显式加载后需要配套释放。


9. UGUI LayoutGroup 频繁变化可能导致布局重建开销。

答案:对

解析:动态列表和复杂布局尤其明显。


10. 为防作弊,客户端计算结果都可以被服务器完全信任。

答案:错

解析:关键状态应由服务器校验或裁决。


四、填空题

1. 实现每秒移动 speed 单位,位移通常写作 speed * ______

答案:Time.deltaTime

解析:deltaTime 表示帧间隔。


2. 暂停界面仍按真实时间播放动画,可使用 Time.______

答案:unscaledDeltaTime

解析:它不受 timeScale 影响。


3. 物理相关更新通常写在 ______ 函数中。

答案:FixedUpdate

解析:FixedUpdate 按固定游戏时间间隔执行。


4. 相机跟随通常可以放在 ______,让目标先完成本帧移动。

答案:LateUpdate

解析:LateUpdate 在 Update 后调用。


5. 判断对象在层级中最终是否激活,应读取 ______。

答案:activeInHierarchy

解析:activeSelf 只表示自身开关。


6. Unity 协程常见返回类型是 ______。

答案:IEnumerator

解析:协程通过 yield 分段执行。


7. 关闭一个 GameObject 通常调用 gameObject.______(false)

答案:SetActive

解析:SetActive 控制对象激活状态。


8. 切场景后仍保留全局管理器,可调用 ______。

答案:DontDestroyOnLoad

解析:常用于 AudioManager、GameManager 等常驻对象。


9. Addressables 显式加载资源后,用完应调用 ______ 释放。

答案:Release

解析:释放 handle 或资源,减少引用计数。


10. 定位 CPU、GC、内存等问题,Unity 常用工具是 ______。

答案:Profiler

解析:先定位瓶颈再优化。


五、代码阅读题

1. 生命周期输出顺序

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Life : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log("Awake");
    }

    private void OnEnable()
    {
        Debug.Log("OnEnable");
    }

    private void Start()
    {
        Debug.Log("Start");
    }
}

答案:Awake、OnEnable、Start

解析:激活对象首次进入场景时,Awake 先于 OnEnable,Start 在第一次 Update 前执行。


2. 值类型复制

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public struct Data
{
    public int Value;
}

public class Test : MonoBehaviour
{
    private void Start()
    {
        Data a = new Data { Value = 1 };
        Data b = a;
        b.Value = 2;
        Debug.Log(a.Value);
    }
}

答案:1

解析:struct 是值类型,赋值会复制一份数据。


3. 引用类型复制

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Data
{
    public int Value;
}

public class Test : MonoBehaviour
{
    private void Start()
    {
        Data a = new Data { Value = 1 };
        Data b = a;
        b.Value = 2;
        Debug.Log(a.Value);
    }
}

答案:2

解析:class 是引用类型,a 和 b 指向同一个对象。


4. for 闭包捕获

阅读代码,写出输出或说明问题:

csharp
using System;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    private void Start()
    {
        List<Action> actions = new List<Action>();
        for (int i = 0; i < 3; i++)
        {
            actions.Add(() => Debug.Log(i));
        }

        foreach (Action action in actions)
        {
            action();
        }
    }
}

答案:3、3、3

解析:for 循环变量被闭包捕获的是同一个变量。需要在循环体内复制局部变量。


5. Transform.position 的值拷贝

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Test : MonoBehaviour
{
    private void Start()
    {
        transform.position = Vector3.zero;
        Vector3 p = transform.position;
        p.x = 10;
        Debug.Log(transform.position.x);
    }
}

答案:0

解析:Vector3 是值类型,修改临时变量 p 不会自动写回 transform.position。


6. activeSelf 与 activeInHierarchy

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject parent;
    public GameObject child;

    private void Start()
    {
        child.SetActive(true);
        parent.SetActive(false);
        Debug.Log(child.activeSelf);
        Debug.Log(child.activeInHierarchy);
    }
}

答案:True、False

解析:child 自身是激活的,但父物体关闭后,它在层级中不激活。


7. timeScale 对 deltaTime 的影响

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Test : MonoBehaviour
{
    private void Update()
    {
        Time.timeScale = 0f;
        Debug.Log(Time.deltaTime == 0f);
    }
}

答案:通常输出 True

解析:deltaTime 受 timeScale 缩放;真实项目中不建议每帧反复设置 timeScale。


8. StringBuilder 引用复用

阅读代码,写出输出或说明问题:

csharp
using System.Text;
using UnityEngine;

public class Test : MonoBehaviour
{
    private void Start()
    {
        StringBuilder builder = new StringBuilder();
        builder.Append("A");
        StringBuilder other = builder;
        other.Append("B");
        Debug.Log(builder.ToString());
    }
}

答案:AB

解析:StringBuilder 是引用类型,other 和 builder 指向同一个对象。


9. 事件订阅未解绑

阅读代码,写出输出或说明问题:

csharp
using System;
using UnityEngine;

public class Bus
{
    public static event Action OnFire;

    public static void Fire()
    {
        OnFire?.Invoke();
    }
}

public class Listener : MonoBehaviour
{
    private void OnEnable()
    {
        Bus.OnFire += Handle;
    }

    private void Handle()
    {
        Debug.Log("Fire");
    }
}

答案:风险:重复启用可能重复订阅,销毁后也可能残留引用

解析:应在 OnDisable 或 OnDestroy 中取消订阅,避免重复回调和生命周期问题。


10. 对象池脏状态

阅读代码,写出输出或说明问题:

csharp
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public int Damage = 10;

    public void Init(int damage)
    {
        Damage = damage;
    }
}

// 某次使用把 Damage 改成 100,回收时没有重置;
// 下次从池里取出后也没有调用 Init。

答案:下次可能仍然是 100

解析:池化对象不会自动恢复默认状态,取出/回收时要明确重置。


六、代码填空题

1. 缓存 Transform,避免每帧重复查找

补全横线处代码:

csharp
using UnityEngine;

public class Mover : MonoBehaviour
{
    private Transform cachedTransform;

    private void Awake()
    {
        cachedTransform = ______;
    }

    private void Update()
    {
        cachedTransform.position += Vector3.forward * Time.deltaTime;
    }
}

答案:transform

解析:常用组件引用可以提前缓存。


2. 对象池取出对象时激活

补全横线处代码:

csharp
public GameObject Spawn()
{
    GameObject obj = pool.Pop();
    obj.______(true);
    return obj;
}

答案:SetActive

解析:从池中取出后通常激活对象。


3. 协程等待 1 秒

补全横线处代码:

csharp
using System.Collections;
using UnityEngine;

public class Test : MonoBehaviour
{
    private IEnumerator Delay()
    {
        yield return new ______(1f);
        Debug.Log("Done");
    }
}

答案:WaitForSeconds

解析:WaitForSeconds 受 timeScale 影响。


4. 字典读取配置,避免重复查找

补全横线处代码:

csharp
if (configs.______(id, out Config cfg))
{
    Apply(cfg);
}

答案:TryGetValue

解析:TryGetValue 可以一次完成查询和取值。


5. Addressables 释放句柄

补全横线处代码:

csharp
private AsyncOperationHandle<GameObject> handle;

private void OnDestroy()
{
    Addressables.______(handle);
}

答案:Release

解析:显式加载的资源要配套释放。


七、简答题

1. 简述对象池的作用和可能问题。

参考答案:对象池通过复用短生命周期对象,减少 Instantiate/Destroy、托管分配、GC 和初始化开销。常见问题是对象状态未重置、池过大导致常驻内存升高、回收时事件/协程/引用未清理、不同类型对象混池造成管理复杂。


2. 简述 Unity 常见生命周期顺序。

参考答案:常见顺序是 Awake、OnEnable、Start、Update、LateUpdate;FixedUpdate 按固定游戏时间间隔执行,不等同于每帧一次;OnDisable 在组件或对象禁用时调用,OnDestroy 在销毁时调用。


3. 协程和线程有什么区别?

参考答案:Unity 协程默认在主线程分段执行,不适合承载耗时 CPU 任务;线程是真正并行执行单元,但不能随意访问 UnityEngine 对象。协程适合等待、流程编排、分帧执行;线程适合纯数据计算或 IO,但要处理同步和回主线程。

题目图示


4. Unity 中动态加载资源有哪些常见方式?

参考答案:常见方式包括 Resources.Load、AssetBundle、Addressables。Resources 使用简单但不适合大规模资源管理;AssetBundle 灵活但依赖和卸载需要自己处理;Addressables 封装地址、依赖、异步加载和引用释放,项目规模大时更常用。


5. UGUI 性能优化可以从哪些方面入手?

参考答案:可以动静分离 Canvas,减少 LayoutGroup 和 ContentSizeFitter 的频繁重建,关闭无用 Raycast Target,长列表使用复用,合并图集和材质,避免每帧刷新所有文本和图片,使用 Profiler/Frame Debugger 定位 CPU 与渲染开销。


6. 游戏客户端模块化设计通常怎么做?

参考答案:可以把资源、UI、网络、配置、音频、战斗、输入、存档等拆成边界清晰的模块。模块之间通过接口、事件或消息通信,避免互相直接拿内部对象。配置和运行时状态分离,方便测试、热更新和问题定位。


7. 遇到移动端偶发卡顿,你会如何分析?

参考答案:先用 Profiler 记录卡顿帧,区分 CPU、GPU、GC、IO、资源加载、Shader 编译、网络回调等原因;再看具体热点函数、GC Alloc、Canvas rebuild、Instantiate/Destroy、纹理上传和同步等待;最后做针对性优化并对比前后数据。


八、场景分析题

1. 场景:战斗中每秒生成大量子弹和命中特效,运行一分钟后开始明显卡顿。请分析原因并给出优化方案。

参考答案:可能原因是频繁 Instantiate/Destroy、粒子和脚本对象分配、GC、特效资源重复加载。优化上应建立子弹池和特效池,回收时停止粒子、解绑事件、清理目标引用,取出时重置位置、伤害、生命周期;资源提前预加载或按波次加载;用 Profiler 对比 GC Alloc、CPU Timeline 和对象数量。

题目图示


2. 场景:背包界面有 3000 个道具格,打开界面卡顿,滑动时掉帧。如何优化?

参考答案:不要一次生成全部格子,应使用虚拟列表,只创建可见区域和少量缓冲 item;动静分离 Canvas,减少 LayoutGroup 重建;图标异步加载并缓存;关闭不需要点击的 Raycast Target;文本和红点只在数据变化时刷新;用 Profiler 观察 Canvas.BuildBatch、Layout、GC Alloc。


3. 场景:切换场景后内存没有下降,甚至越切越高。请列出排查步骤。

参考答案:先确认旧场景对象是否被 DontDestroyOnLoad 或静态引用持有;检查 Addressables/AssetBundle handle 是否 Release;检查对象池是否无限扩张;检查事件订阅、单例、缓存字典是否持有场景对象;使用 Memory Profiler 对比快照,查看纹理、Mesh、AudioClip、GameObject 和托管对象引用链。

文章评价

读完这篇,留下你的看法

暂无审核通过的评价。

登录账号后才能评价。

本站访客数0总站访问量0本页访问量0