1. 文本文件打开后乱码,一般是什么原因?

文本乱码最常见的原因是读写两端的字符编码不一致。例如文件按 UTF-8 写入,却按 GBK 读取。解决方式是明确统一项目文本编码,并在读写 API 中显式指定 Encoding。跨平台项目通常优先统一使用 UTF-8;另外也要注意文件是否带 BOM,以及字体是否缺少对应字符字形。

2. C# 中 new 关键字的作用

  • new 最常见的作用是创建对象实例,并调用对应构造函数;第二是创建数组并分配数组空间;第三是创建值类型或泛型集合等实例。
  • 此外,在泛型约束中 where T : new() 表示类型必须具备无参构造能力,方法内部才能写 new T()。
  • 对引用类型来说,new 通常会创建托管堆对象;但具体内存布局仍应结合运行时和逃逸分析理解,不能机械地只记“new 一定在堆上”。

3. 同步与异步的区别;何时使用异步

  • 同步方法会让调用方按顺序等待结果;异步方法会先发起耗时操作,当前流程不必阻塞,等操作完成后再继续处理结果。
  • 异步编程的目标主要是避免主线程因为 I/O 或耗时工作而卡顿,并不代表一定创建新线程。
  • 在 Unity 中,网络请求、资源加载、文件读写、场景切换,以及可脱离 Unity API 的复杂计算,都适合考虑异步。需要注意 Unity 的大部分对象和 API 只能在主线程访问,因此后台计算得到结果后,要切回主线程更新场景和 UI。

4. 回调函数是什么?何时使用?

  • 回调函数是把一段后续逻辑作为参数传给另一个方法,由被调用方在合适时机执行。本质上常通过委托、Action、Func 或事件实现。
  • 它适合调用方无法确定操作何时完成,但完成后需要继续处理的场景,例如网络回包、异步资源加载、动画结束、UI 交互和对象池回收。
  • 使用回调时我会注意职责边界:一次性结果通知适合回调;多个对象长期订阅的通知更适合事件;复杂异步流程则更适合 Task 和 async/await,避免回调嵌套过深。

5. 如何用一个 int 记录 32 种可并存状态?

  • 可以把 int 当作 32 个二进制开关位,每一位对应一种状态,并使用 [Flags] 枚举定义 1 < < n 的值。添加状态使用按位或,移除状态使用按位与加取反,判断状态使用按位与。
  • 这种方式适合中毒、眩晕、减速、无敌这类“是否存在”的开关状态,内存占用小、判断快。持续时间、层数、数值和来源等运行时数据仍然需要单独维护。

6. Prefab 是什么?有什么作用?

  • Prefab 是 Unity 中可复用的 GameObject 资源模板,它保存对象层级、组件、引用关系和序列化配置。我们可以在场景中创建 Prefab 实例,也可以在运行时通过 Instantiate 创建。
  • 它的作用是统一管理可重复使用的对象,例如角色、敌人、子弹、UI Item、特效和交互物。Prefab 能保证对象结构一致,减少重复配置;同时也支持 Prefab Variant,用于在保留基础模板结构的前提下做差异化配置。
  • 实际项目中,Prefab 更适合保存稳定的表现和组件结构;频繁变化的数值规则通常放在 ScriptableObject 或配置表中管理。

7. Shader 是什么?有什么作用?如何写基本 Shader?

  • Shader 是运行在 GPU 上的着色程序,用来决定网格如何被绘制。它通常包括顶点阶段和片元阶段:顶点阶段负责顶点变换等处理,片元阶段负责计算每个像素的最终颜色。
  • Shader 可以控制纹理采样、颜色、透明、光照、阴影、深度测试和混合等效果;材质球则是 Shader 的一组具体参数。
  • 在 Unity 中,简单项目或常规特效我会优先使用 URP 的 Shader Graph;当需要自定义顶点动画、特殊光照、屏幕特效或性能精细控制时,再用 HLSL 编写 Shader。一个基础 Shader 至少需要完成顶点坐标变换,并在片元阶段输出颜色或纹理采样结果。

8. 常见性能优化技巧

  • Unity 性能优化要先通过 Profiler、Frame Debugger 和真机数据确认瓶颈,再分别处理 CPU、GPU、内存和加载问题。
  • CPU 方面可以减少高频查找、缓存引用、集中管理高数量对象更新;GPU 方面可以减少不必要的 Draw Call 和 Overdraw,使用 LOD、合批、GPU Instancing、纹理压缩;内存方面要减少每帧 GC Alloc,复用集合和对象池;加载方面则使用异步加载、分帧实例化和按需释放。
  • 例如大量敌人不应该每帧全局查找目标,而应该维护注册列表或空间查询结构。优化的原则不是套技巧,而是先明确是哪一类资源成为瓶颈。

9. Coroutine 是什么?有什么作用?如何使用?

  • 协程是 Unity 基于 IEnumerator 实现的分帧流程控制机制。它可以在 yield return 处暂停,并在下一帧、指定时间后、物理帧后或异步操作完成后恢复执行。
  • 它适合技能流程、延时逻辑、分批生成、渐变动画、异步加载等待等场景。协程本身不是多线程,里面直接访问 Unity API 仍然是在主线程;因此它解决的是“把流程拆到多个时机执行”,不是把 CPU 重计算放到后台。
  • 使用时要注意生命周期,例如对象销毁、界面关闭或状态切换时应停止不再需要的协程,避免旧流程继续修改当前状态。

10. 什么是渲染管线?如何使用?应用场景

  • 渲染管线是 Unity 把场景中的模型、材质、灯光、阴影和相机信息转换成最终屏幕图像的一套流程。它包括可见物体筛选、绘制调用、顶点和片元处理、深度测试、混合、后处理等阶段。
  • Unity 常见的管线有内置管线、URP 和 HDRP。URP 更适合移动端、2D 和跨平台项目,性能与画面效果比较均衡;HDRP 面向高端 PC 和主机的高质量写实渲染;内置管线更多见于旧项目维护。
  • 实际开发中,我会根据目标平台、画面需求、团队已有 Shader 和美术资源确定管线。例如移动端 2D 项目一般选择 URP 的 2D Renderer,再结合 2D Light、Shader Graph 和 Renderer Feature 实现光照与特效。