面试归档1

1. 请说出 Lua 中常用的数据类型,至少说出 6 种

标准答案

Lua 中常用的数据类型有 nilbooleannumberstringtablefunctionuserdatathread

其中,nil 表示空值;boolean 表示布尔值;number 表示数字;string 表示字符串;table 是 Lua 中最重要的数据结构,可以用来表示数组、字典和对象;function 表示函数,Lua 中函数是一等值;userdata 通常用于 Lua 和 C/C++ 或 C# 交互;thread 表示协程类型。

面试中可以这样说:

Lua 常用的数据类型有 nilbooleannumberstringtablefunctionuserdatathread。其中 table 是 Lua 最核心的数据结构,数组、字典、对象都可以用它实现;函数在 Lua 中也是一等值,可以赋值、传参和返回。


2. Lua 中 pairs 和 ipairs 的区别

标准答案

pairsipairs 都可以遍历 table,但它们的遍历规则不同。

ipairs 主要用于遍历数组部分,它会从下标 1 开始,按照连续整数 key 依次遍历,遇到第一个 nil 就会停止。

pairs 用于遍历 table 中的所有键值对,包括数字 key、字符串 key 等,但遍历顺序是不确定的。

面试中可以这样说:

ipairs 适合遍历连续数组,从下标 1 开始,遇到 nil 就停止;pairs 适合遍历 table 中所有键值对,包括字符串 key 和不连续的数字 key,但是遍历顺序不保证。


3. Lua 中常用的元方法有哪些?至少说出 3 个元方法

标准答案

Lua 中常用的元方法有:

  • __index:访问 table 中不存在的字段时触发,常用于实现继承、默认值和方法查找。
  • __newindex:给 table 中不存在的字段赋值时触发,常用于赋值拦截、只读表或数据绑定。
  • __call:让 table 可以像函数一样被调用。
  • __tostring:控制 table 或对象转成字符串时的表现。
  • __add:重载加法运算符。
  • __sub:重载减法运算符。
  • __eq:重载相等比较。
  • __gc:垃圾回收时触发,常用于 userdata 的资源清理。

面试中可以这样说:

Lua 常用的元方法有 __index__newindex__call__tostring__add__eq 等。比如 __index 常用于实现继承和方法查找,__newindex 可以拦截赋值,__call 可以让 table 像函数一样调用。


4. Lua 中元表的作用

标准答案

元表可以理解为给 table 附加的一套特殊行为规则。Lua 中的 table 本身比较简单,但通过元表和元方法,可以实现很多类似面向对象和运算符重载的能力。

元表常见作用包括:实现继承、实现默认值、拦截字段访问、拦截字段赋值、实现运算符重载、让 table 像函数一样调用、自定义字符串输出等。

面试中可以这样说:

元表的作用是给 table 定义额外的行为规则。通过元表中的元方法,可以实现字段访问拦截、赋值拦截、运算符重载、默认值、继承等效果。在 Lua 的面向对象写法中,元表非常常见,尤其是通过 __index 实现对象方法查找和继承。


5. Lua 中 __index 和 __newindex 有什么作用

标准答案

__index__newindex 都是 Lua 元表中非常重要的元方法。

__index 会在访问 table 中不存在的字段时触发。它可以是一个 table,也可以是一个 function。如果 __index 是 table,Lua 会去这个 table 中继续查找字段;如果是 function,就会调用这个函数并返回结果。它常用于实现继承、默认值和方法查找。

__newindex 会在给 table 中不存在的字段赋值时触发。它也可以是 table 或 function,常用于属性赋值拦截、只读表、数据绑定等场景。

需要注意的是,只有字段不存在时才会触发 __index__newindex。如果字段本身已经存在,普通访问和赋值不会触发这些元方法。

面试中可以这样说:

__index 是访问 table 中不存在字段时触发,常用于继承、默认值和方法查找;__newindex 是给 table 中不存在字段赋值时触发,常用于赋值拦截、只读表和数据绑定。需要注意,只有字段不存在时才会触发它们。


6. Unity 中判断两个 2D 矩形是否相交,有几种方式?请至少说出两种方式

标准答案

Unity 中判断两个 2D 矩形是否相交,常见有两类方式:一种是数学层面的矩形判断,另一种是使用 Unity 的物理或 API。

第一种方式是使用 Rect.Overlaps。如果两个矩形可以用 Unity 的 Rect 表示,比如 UI 区域或逻辑矩形,可以直接使用 rectA.Overlaps(rectB) 判断两个矩形是否重叠。

第二种方式是使用 AABB 判断。对于没有旋转的矩形,可以比较两个矩形的 xMinxMaxyMinyMax。只要一个矩形没有完全在另一个矩形的左边、右边、上边或下边,就说明它们相交。

第三种方式是使用 Unity 的 2D 物理系统。如果是场景中的 GameObject,并且挂了 BoxCollider2D,可以通过 OnTriggerEnter2DOnCollisionEnter2DPhysics2D.OverlapBox 判断是否发生重叠。

面试中可以这样说:

Unity 中判断两个 2D 矩形是否相交,要看矩形来源。如果是 UI 或普通逻辑矩形,可以使用 Rect.Overlaps,也可以自己用 AABB 方式比较四条边。如果是场景中的 2D 物体,可以使用 BoxCollider2D 配合 OnTriggerEnter2DOnCollisionEnter2D,或者使用 Physics2D.OverlapBox 来判断。


7. Unity 中想要制作角色的连招功能,在制作状态机时一般如何处理?

标准答案

Unity 中制作角色连招时,一般会把每一段攻击设计成独立状态,比如 Attack1Attack2Attack3

玩家按下攻击键后进入第一段攻击。在攻击动画播放到某个阶段时,开启连招输入窗口。如果玩家在窗口期内再次按下攻击键,就记录或缓存这次输入,然后在当前攻击动画播放到合适节点时切换到下一段攻击。

如果玩家没有在窗口期内输入,当前攻击播放结束后就回到 Idle 状态。

实际项目中,连招窗口、伤害判定、攻击位移、是否允许转向、是否允许被打断等,通常可以通过动画事件、normalizedTime 或配置表来控制。

面试中可以这样说:

Unity 中做角色连招时,一般会把每一段攻击设计成独立状态,比如 Attack1Attack2Attack3。玩家按攻击键后进入第一段攻击,在动画播放到某个阶段时开启连招输入窗口。如果玩家在窗口期内再次按攻击键,就先缓存输入,然后在当前动画播放到合适节点时切换到下一段攻击。如果没有继续输入,攻击结束后回到 Idle。实际项目里,一般会把战斗逻辑放在代码状态机或技能系统中,Animator 主要负责动画表现。


8. Unity 中如果想要在动作的某一时刻进行伤害检测,应该怎么做?请说出两种做法

标准答案

Unity 中如果想在动作的某一时刻进行伤害检测,常见有两种做法。

第一种是使用 Animation Event。可以在攻击动画的关键帧上添加动画事件,当动画播放到挥刀命中的那一帧时,调用伤害检测方法。检测方式可以是 Physics2D.OverlapBoxPhysics2D.OverlapCircle、射线检测,或者 3D 中的 Physics.OverlapBox 等。

第二种是通过代码判断动画播放进度。比如使用 AnimatorStateInfo.normalizedTime 获取当前动画播放百分比,当动画播放到指定时间点或时间段时,执行伤害检测。这种方式更适合做配置化,可以把技能的伤害帧、判定范围、持续时间写进配置表。

还可以补充一种做法:在攻击帧开启武器或攻击范围的 Trigger Collider,在攻击结束帧关闭,通过 OnTriggerEnter2DOnTriggerEnter 判断是否命中敌人。

面试中可以这样说:

Unity 中想在动作某一时刻进行伤害检测,第一种方式是使用 Animation Event,在攻击动画的命中帧调用伤害检测函数,比如使用 OverlapBoxOverlapCircle 检测敌人。第二种方式是通过代码判断动画播放进度,比如使用 normalizedTime,当动画播放到指定百分比时执行检测。实际项目中也可以在攻击帧开启攻击碰撞盒,在攻击结束时关闭。还要注意同一次攻击不要重复命中同一个目标,可以用命中列表做去重。


9. Unity 中想要制作自动寻路逻辑,应该怎么做?请至少说出两种做法

标准答案

Unity 中制作自动寻路逻辑,常见有两种做法。

第一种是使用 Unity 自带的 NavMesh。先在场景中烘焙导航网格,标记哪些区域可以行走,然后给角色添加 NavMeshAgent,通过 SetDestination 设置目标点,让 Unity 自动计算路径并驱动角色移动。这个方案适合普通 3D 场景中的 NPC、怪物追踪和 AI 移动。

第二种是自己实现寻路系统。可以把地图抽象成格子地图、路点网络或节点图,每个节点记录是否可通行,以及和相邻节点的连接关系。然后使用 A*、Dijkstra 或 BFS 等算法计算从起点到终点的路径。

A* 算法中常见的代价计算是 F = G + H。其中 G 表示从起点到当前节点的实际代价,H 表示当前节点到目标点的预估代价,F 是综合代价,搜索时优先选择代价更低的节点。

面试中可以这样说:

Unity 中制作自动寻路,第一种方式是使用 Unity 自带的 NavMesh。通过烘焙导航网格和 NavMeshAgent.SetDestination 实现角色自动寻路,适合普通 3D 场景中的 NPC 或怪物移动。第二种方式是自己实现寻路系统,比如把地图抽象成格子、路点或节点图,然后使用 A* 算法计算路径。A* 通常通过 F = G + H 评估节点,适合 2D、战棋、塔防或需要自定义寻路规则的项目。


10. 游戏编辑器,比如角色编辑器、关卡编辑器、地图编辑器等工具的本质是什么?

标准答案

游戏编辑器的本质是内容生产和数据编辑工具。

它把游戏中的角色、关卡、地图、怪物、技能、触发器等内容,以可视化、配置化的方式提供给开发者、策划或美术编辑。编辑器本身通常不是最终的游戏逻辑,而是负责生成、校验、保存和导出数据。

比如角色编辑器可以编辑角色属性、技能、模型、动画、特效和音效配置;关卡编辑器可以摆放怪物、出生点、机关、触发器和奖励点;地图编辑器可以编辑地形、格子、障碍物、寻路区域和资源点。

这些编辑结果最终通常会保存成 JSON、XML、CSV、二进制文件、ScriptableObject、Prefab、场景文件或自定义配置表。游戏运行时再读取这些数据,并根据数据生成真正的游戏内容。

面试中可以这样说:

游戏编辑器的本质是内容生产和数据编辑工具。它把角色、关卡、地图、怪物、技能、触发器等游戏内容,以可视化和配置化的方式提供给开发者、策划或美术编辑。编辑器本身通常不直接等于游戏运行逻辑,而是负责生成、校验、保存和导出数据。游戏运行时再读取这些数据生成真正的内容。一个好的编辑器还应该考虑数据校验、预览、导入导出、撤销重做、版本兼容和团队协作。