MIL18——模拟面试题

C#

  1. 父类中定义了一个静态成员属性有两个子类都继承该父类请问打印结果是什么?为什么
  2. 泛型父类中定义了一个静态成员属性有两个子类都继承该泛型父类请问打印结果是什么?为什么
  3. 使用 C# 制作游戏存档功能,请问有几种做法?(至少说出三种)
  4. C# 中是否可以通过反射获取到类内部的私有成员?
  5. 在制作游戏存档功能时,C# 中反射主要可以发挥出哪些作用(至少说出三点)

Unity

  1. 如果在 Unity 当中制作 FPS 游戏,如何模拟枪械开枪时的后坐力
  2. Unity 当中存在多线程时,继承 MonoBehaviour​ 的脚本是否有必要对其中内容加锁?为什么?
  3. 我们在 Unity 中进行一些复杂逻辑处理时,比如网路通讯、寻路算法、往往会开启多线程进行处理。
    我们如何保证数据能够和 Unity 主线程进行正常交互?(请至少说出 1 种方式)
  4. Shader 当中的 Blend​ 渲染命令主要用来干什么?
  5. Shader 当中的 Blend​ 渲染命令后面跟的参数是用来干嘛的?比如:Blend SrcAlpha OneMinusSrcAlpha

答案

C#

  1. 父类中定义了一个静态成员属性有两个子类都继承该父类请问打印结果是什么?为什么

    imageimage

    1
    2
    3
    30
    30
    30

    答案: 因为静态成员属于类而不是实例

  2. 泛型父类中定义了一个静态成员属性有两个子类都继承该泛型父类请问打印结果是什么?为什么

    imageimage

    1
    2
    3
    4
    0
    20
    20
    30

    因为静态成员属于类而不是实例,而泛型 T​ 的变化,会让父类"类型"变化(也就是说,Father<Son1>​ 和 Father<Son2>​)
    不同类型的泛型实例,它们的静态成员 static_I​ 是分别存在的,不会相互影响

  3. 使用 C# 制作游戏存档功能,请问有几种做法?(至少说出三种)

    • xml
    • json
    • 2进制
    • 自定义文档结构
    • 数据库

    等等

  4. C# 中是否可以通过反射获取到类内部的私有成员?

    在获取成员的相关方法中,可以通过传入参数,指定获取非公共的成员,
    其中的关键知识是,利用 BindingFlags​ 枚举,其中常用枚举类型是

    • Public​(BindingFlags.Public​): 包括公共成员。
    • NonPublic​(BindingFlags.NonPublic​):包括非公共成员。
    • Instance​(BindingFlags.Instance​):包括实例成员。
    • Static​(BindingFlags.Static​):包括静态成员。
    • FlattenHierarchy​(BindingFlags.FlattenHierarchy​):在层次结构中查找成员,包括继承的成员。
    • IgnoreCase​(BindingFlags.IgnoreCase​):忽略成员名称的大小写

    非公共的成员可通过以下枚举组合获取:BindingFlags.NonPublic | BindingFlags.Instance

  5. 在制作游戏存档功能时,C# 中反射主要可以发挥出哪些作用(至少说出三点)

    1. 序列化时:动态获取数据结构类信息,可以动态获取字段用于存储
    2. 反序列化时:可以通过反射实例化对象,写入数据
    3. 结构发生变化时:我们可以利用反射机制进行判断,多的数据抛弃,少的数据自定义初始化

Unity

  1. 如果在 Unity 当中制作 FPS 游戏,如何模拟枪械开枪时的后坐力

    每次开枪时,可以给枪械、手臂 IK、摄像机等(根据实际视角情况决定) 一个绕 X 轴(往上偏移)和 Y 轴(左右偏移)的旋转角度
    并且每帧都会归位(角度四元数不停向原始位置归位)

  2. Unity 当中存在多线程时,继承 MonoBehaviour​ 的脚本是否有必要对其中内容加锁?为什么?

    分情况讨论:

    1. 如果是想要通过多线程控制或访问场景上对象的相关行为,比如移动旋转、资源加载、动态销毁等等,那么不用加锁

      因为 Unity 的整个执行模型是单线程的,所有的游戏逻辑和渲染都在主线中进行。
      大部分的 Unity API 都只能在主线程上调用,如果通过多线程去调用 Unity 场景上物体的相关API,
      或改变场景中对象的相关属性,会直接出现报错。因此加锁也没有意义

    2. 如果是想要通过多线程改变继承 MonoBehaviour​ 脚本中的某些公共成员,比如一个 int​,一个 List​。
      那么可以为这些公共成员加锁,防止线程并发带来的问题,
      但是建议尽量不要通过多线程和继承 MonoBehaviour​ 的挂载在场景对象中的脚本打交道

  3. 我们在 Unity 中进行一些复杂逻辑处理时,比如网路通讯、寻路算法、往往会开启多线程进行处理。
    我们如何保证数据能够和 Unity 主线程进行正常交互?(请至少说出 1 种方式)

    1. 对共享数据加锁,避免多线程并发带来的数据竞争问题
    2. 用 C# 中线程安全的数据结构存储共享数据,
      比如 System.Collections.Concurrent​ 命名空间中的 ConcurrentQueue<>​ 和 ConcurrentDictionary<>
    3. 可以尝试使用 Unity 当中的 DOTS 系统

    等等

  4. Shader 当中的 Blend​ 渲染命令主要用来干什么?

    用来进行颜色混合的,将当前片元的颜色和颜色缓冲区中的颜色进行混合计算,一般可以用来实现半透明相关效果,光照颜色叠加相关效果等等

  5. Shader 当中的 Blend​ 渲染命令后面跟的参数是用来干嘛的?比如:Blend SrcAlpha OneMinusSrcAlpha

    Blend​ 混合命令后面跟的参数有两种写法,这些因子其实就是一些特定的数,用于参与混合计算

    • 写法一:

      • 输出颜色rgb = 源因子 * 片元颜色的rgb + 目标因子 * 颜色缓冲区中颜色的rgb
      • 输出颜色a = 源透明因子 * 片元颜色的a + 目标透明因子 *颜色缓冲区中颜色的a
    • 写法二:

      • 输出颜色rgb = 源因子 * 片元颜色的rgb + 目标因子 * 颜色缓冲区中颜色的rgb
      • 输出颜色a = 源因子 * 片元颜色的a + 目标因子 * 颜色缓冲区中颜色的a