MIL23——模拟面试题

C#

  1. int[,] strArray = new int[3, 4]​ 这个语句创建了多少个 int​ 对象?
    string[,] strArray = new string[3, 4]​ 这个语句创建了多少个 string 对象?
  2. 为什么我们要尽量避免装箱拆箱?避免装箱拆箱的方案有哪些?
  3. 为什么说闭包可能会带来内存泄漏?
  4. 单机游戏中,我们如何避免玩家利用修改器修改客户端数据?(至少说出2点方案)
  5. 网络游戏中,我们如何避免外挂的产生?(至少说出2点方案)

Unity

  1. Transform​ 中的本地坐标系的方向 转换 为相对世界坐标系的方向 的两个API
    TransformVector()​ 和 TransformDirection() 有什么区别?
  2. Lua 语言中的 upvalue 是什么?
  3. 该 Unity 中的报错是什么意思?如何定位该问题?我们一般如何排查解决该问题?(至少说出2种方案)
  4. 在 Android 平台上运行的项目出现问题,我们有几种调试的方式?(至少说出 3 种方案,不使用第三方插件)
  5. 使用 UnityWebRequest 加载音效文件,应该使用什么API?

答案

  1. int[,] strArray = new int[3, 4]​ 这个语句创建了多少个 int​ 对象?
    string[,] strArray = new string[3, 4]​ 这个语句创建了多少个 string 对象?

    1. 12个 int 对象
    2. 0个 string 对象
  2. 为什么我们要尽量避免装箱拆箱?避免装箱拆箱的方案有哪些?

    首先回答装箱拆箱的概念,装箱是把值类型转换为引用类型的过程,拆箱是把引用类型转换回值类型的过程
    避免它们的原因是:

    1. 会增加内存消耗:在堆上分配新对象来存储值类型
    2. 会增加性能消耗:装箱创建的新对象会增加垃圾回收 GC 的负担,可能会加快 GC 的触发
    3. 存在错误风险:如果拆箱时类型不匹配可能会报错

    避免方案:

    1. 泛型
    2. 里式替换原则

    等等

  3. 为什么说闭包可能会带来内存泄漏?

    闭包可能会捕获并持有外部作用域变量的引用。 这些引用会导致外部作用域的对象持续存在,即使它们不再需要。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class B
    {
    private static B instance = new B();
    public static B Instance => instance;
    public Action callback;
    public void DoSomething(Action action) => this.callback = action;
    }

    public class A
    {
    public void Test() => B.Instance.DoSomething(() => this.Speak());
    public void Speak() {}
    }

    public void Main()
    {
    A a = new A();
    a.Test();
    a = null;
    }
  4. 单机游戏中,我们如何避免玩家利用修改器修改客户端数据?(至少说出 2 点方案)

    1. 数据加密,对存档数据和内存中关键数据进行加密 让玩家无法通过修改软件准确找到对应游戏数据
    2. 混淆代码,增加破解难度
    3. 检测修改器,运行时检测常见修改器,警告或强行退出游戏
    4. 服务器验证存储

    等等

  5. 网络游戏中,我们如何避免外挂的产生?(至少说出2点方案)

    1. 服务器验证,尽量将游戏逻辑和关键数据通过服务器进行处理
    2. 通讯数据加密,避免数据被篡改
    3. 客户端和服务器进行频繁的数据验证
    4. 使用反外挂服务,利用第三方的一些定制反外挂软件和服务来检测和组织常见外挂工具
    5. 玩家行为数据行为分析,识别异常数据和行为进行封号等惩罚
    6. 检测客户端完整性,看客户端文件是否被篡改

Unity

  1. Transform​ 中的本地坐标系的方向 转换为 相对于世界坐标系的方向 的两个API
    TransformVector()​ 和 TransformDirection() 有什么区别?

    • TransformDirection 不受缩放影响

      该操作不受变换的缩放或位置的影响。 返回的矢量与 direction​ 的长度相同。
      如果矢量表示位置而不是方向,则应使用 Transform.TransformPoint 进行转换。

    • TransformVector 受缩放影响

      该操作不受变换的位置的影响,但受缩放影响。 返回的矢量可能具有与 vector 不同的长度。

  2. Lua 语言中的 upvalue 是什么?

    upvalue​ 是一个闭包概念,被局部函数所捕获的外部变量就叫 upvalue
    一般情况下,一个函数的外部作用域中定义了一个变量,但是其被该函数所引用了,那么这种变量就被称为 upvalue,比如:

    1
    2
    3
    4
    5
    6
    function outerFunction()
    local outerVariable = 10
    return function innerFuntcion()
    print(outerVariable) -- 这里的 outerVariable 就是 upvalue
    end
    end
  3. 该 Unity 中的报错是什么意思?如何定位该问题?我们一般如何排查解决该问题?(至少说出 2 种方案)

    • 该报错的意思是:对象引用为设置为对象的实例(空引用)

    • 打印信息中有具体报错的脚本以及代码行数:Test.cs:11,我们可以双击该报错快速定位报错位置

    • 排查解决方案:

      1. 检查上下逻辑,判断对象为何会为空(是否初始化、是否置空,执行时机是否在初始化之前,置空之后)
      2. 断点一步步排查逻辑走向,定位问题
      3. 加入打印信息,检查逻辑执行的先后顺序(利用打印信息判断执行时机是否在初始化之前,置空之后)
      4. 如何确定执行时机呢?我们可以选中这个变量 Shift+F12 再整个工程中查看哪些地方对该变量进行了使用,
        然后在特定的位置进行断点、打印等等方式进行调试
  4. 在 Android 平台上运行的项目出现问题,我们有几种调试的方式?(至少说出 3 种方案,不使用第三方插件)

    1. Unity 内调试安卓应用程序(发布安卓应用时进行对应的设置,可以直接在 Unity 中进行断点、性能检测窗口调试)
    2. Unity Remote(主要用于调试输入相关、相机拍照相关功能)
    3. 在 Android Studio 中进行调试(Unity 打包时打包为 Android Studio 工程)
    4. 利用 Unity 中的 Android Logcat 工具进行调试,获取重要信息
    5. 利用 ADB(Android Debug Brige 安卓调试桥)工具进行调试,获取重要信息 等等
  5. 使用 UnityWebRequest 加载音效文件,应该使用什么API?

    我们应该使用 UnityWebRequest​ 提供的专门用于获取媒体信息的 API UnityWebRequestMultimedia.GetAudioClip​ 进行获取
    获取成功后,应该使用 DownloadHandlerAudioClip.GetContent​ 来获取 AudioClip