ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

西山居游戏开发岗笔试复盘:从C++基础到图形学与游戏逻辑设计

2026/8/29 23:47:26 拓冰建站 浏览量
西山居游戏开发岗笔试复盘:从C++基础到图形学与游戏逻辑设计 去年秋招我投了西山居的游戏开发岗笔试是在一个工作日的晚上进行的。打开在线测评链接的时候我还以为自己准备得挺充分——LeetCode刷了两百多道C八股背了好几轮。结果题目加载出来的那一刻我盯着屏幕愣了好一会儿这卷子和普通互联网大厂的笔试题完全是两个物种。整场笔试两个小时题型既有选择题也有代码题还有让我现场设计游戏逻辑的题。说实话那两小时比我在球场打一下午全场还累。这篇文章就是想把这份笔试的完整复盘写出来。适合谁看如果你准备投游戏公司的技术岗尤其是西山居这类有自研引擎、做大型MMO的厂商这份经验能帮你把复习方向从通用算法题掰回到游戏开发场景上。我会把考察侧重点、典型题型、现场时间分配、以及我踩过的坑全部拆开来讲。1. 笔试前必须先摸清的岗位方向与考察侧重点很多人拿到笔试邀请就开始刷题这是最大的误区。游戏开发岗不是一个笼统的岗位它内部至少可以拆成客户端开发、引擎开发、服务端开发三个方向每个方向笔试试卷的侧重点差异很大。你投的到底是哪个方向决定了你的复习重心。1.1 客户端、引擎、服务端三套不同的考察思路西山居目前的业务线里既有《剑网3》这种基于自研引擎的端游项目也有《尘白禁区》这类Unity技术路线的产品。客户端开发更多关注玩法系统实现、UI逻辑、战斗表现、场景交互引擎开发则会更深入地考察渲染管线的理解、资源管理、内存布局、跨平台适配服务端方向更侧重高并发、数据库、网络同步、分布式状态管理。笔试虽然是一张卷子但每个方向的题目占比是有讲究的。我印象比较深的一点是客户端方向的题目里场景管理和物体交互的代码题会多一些引擎向的岗位图形学和内存相关的内容会明显加重。服务端方向虽然也有C题目但多线程、锁、网络协议的比例会更高。提示投简历的时候确认一下邮件里标注的技术栈关键词。如果写的是U3D客户端那Unity生命周期、组件系统、物理射线检测几乎必考如果写的是引擎研发那图形学基础的分量会重很多。1.2 从笔试邀请里反推复习优先级笔试邮件里通常会有几个关键信息总时长、题型说明、编程语言限制、是否允许本地IDE。这些信息都能帮你规划复习策略。总时长两小时题目数量在三十题左右意味着选择题不能恋战平均每题只有几十秒。允许使用的编程语言一般明确写了C个别岗位会放宽到C#。如果你只会刷Python的算法题这时候会很难受——很多游戏开发岗位笔试根本不给Python选项。题目如果包含游戏场景/逻辑设计类的主观题一般不是考察你背了多少API而是看你面对一个开放性问题时能不能把问题拆解成可实现的系统模块。我当时就是从邮件里看到线下笔试仅允许C含图形学基础题这几个字才意识到复习方向必须从纯刷题转向游戏开发视角的C。如果你现在还没收到笔试邀请建议先按这个思路去准备比临时抱佛脚强得多。1.3 游戏公司笔试到底在筛什么样的人这是很多人没想明白的问题。游戏开发岗笔试和互联网通用后端笔试的核心区别在于前者更看重空间想象能力、场景抽象能力和对实时系统的敏感性。同样是考算法游戏公司会把它包装成场景里有N个敌人怎么快速找到玩家周围的敌人同样是考C它会问你一个游戏对象池怎么实现才能避免频繁new和delete导致的性能抖动。换句话说游戏公司笔试筛选的不是刷题机器而是具备游戏开发思维的人。这种思维包括理解CPU与内存对实时渲染帧率的影响理解Update和FixedUpdate的差异对物理模拟的意义理解为什么游戏服务器需要做状态同步而Web后端大多不需要。这些东西不是靠最后一晚突击能补上的需要提前一两个月开始用游戏开发的眼睛去审视你学过的每一个知识点。2. 题型地图三块内容各自在考你的什么能力把笔试当成一个完整的关卡来解首先要看它的关卡组成。西山居游戏开发岗的笔试题型我把它归纳成三大块选择题、编程题、游戏逻辑/设计题。每一块的考察目标完全不同答题策略也完全不同。2.1 选择题基础不牢的照妖镜选择题的覆盖面非常广但难度通常不会超过概念理解层面。常见的出题点包括C语言基础虚函数机制、智能指针用法、const修饰符、左值右值与移动语义、模板特化。数据结构与算法概念排序算法的时间复杂度、哈希表冲突处理、红黑树和AVL树的区别、堆与栈的区别。操作系统基础进程与线程的区别、死锁的四个必要条件、虚拟内存、页表。计算机图形学基础渲染管线的几个阶段、透视投影与正交投影的区别、颜色空间、纹理采样与过滤方式。游戏引擎常识Unity的脚本生命周期、预制体的概念、场景管理方式、资源加载与卸载。这里有个很重要的判断选择题考的不是你背得熟不熟而是你在考试压力下能不能快速回忆起概念并做出判断。游戏开发是实时交互系统代码出Bug不会等你慢慢想所以笔试中设置大量选择题模拟的就是那种需要在短时间内做出准确判断的工作状态。2.2 编程题从暴力到优化的完整踩分逻辑编程题一般是两到三道难度从经典算法题到游戏场景包装题不等。很多人一看到游戏场景包装就直接发懵其实剥开包装之后核心算法往往是你见过的经典模型。举个例子题目可能会这样出你设计一个塔防游戏地图上有若干个防御塔每个塔有固定的攻击范围现在给你一批怪物的坐标要求快速判断每个怪物会被哪些塔攻击。剥开这层皮本质就是一个空间范围查询问题可以用网格分桶、四叉树或空间哈希来解决。如果你只学了裸的算法没有做过把算法嵌入到游戏逻辑的训练这种包装题很容易把你带偏。编程题的判分方式也值得注意。在线笔试的判题系统一般不会因为你的代码编译不过就直接给零分很多时候是按测试用例通过比例给分的。这意味着即使你只能写一个暴力解法也要把它写出来提交至少能拿到一部分分数。2.3 游戏逻辑/设计题笔试真正的分水岭这一块是我认为最能拉开差距的部分。它通常不是让你写完整代码而是给你一个开放式的游戏设计问题要你用文字或伪代码描述你的实现思路。我考完复盘这类题的核心套路可以归纳成三步拆解需求、确定技术选型、描述容错方案。拆解需求就是要把题目描述中的高维目标拆成可执行的功能模块。确定技术选型就是针对每个模块选择合适的工具或实现路径。描述容错方案是很多应届生最容易忽略的——比如如果一个玩家掉线了下次重连回来他的状态应该怎么恢复。游戏是和人打交道的系统异常处理比功能实现更能体现工程能力。3. C与数据结构的常考考点附一道典型题的完整复盘既然游戏开发岗笔试普遍限制C那C语言本身的功底就是第一道关。这一节我结合西山居笔试的考察风格挑几个核心考点展开讲并拆解一道非常典型的编程题解题过程。3.1 C基础为什么反复被问虚函数、智能指针、内存管理游戏客户端对性能极度敏感C的每一个语言特性都直接和内存布局、CPU缓存、虚函数调用的开销挂钩。虚函数与多态场景中可能有几十种敌人类型都用基类指针管理。虚函数表怎么布局虚函数调用的性能开销在哪里为什么有些游戏引擎会尽量减少虚函数调用次数智能指针与内存管理Unity有自动GC但C引擎中内存管理完全交给开发者和智能指针。shared_ptr的循环引用问题怎么解决weak_ptr在场景对象的观察者模式中有什么作用游戏场景中一个敌人被销毁了但它还被技能系统引用着这个悬垂引用怎么避免移动语义与右值引用渲染线程每帧会创建大量的临时变量如果在传递过程中触发深拷贝性能会急剧下降。移动语义做字符串、容器的零拷贝传递是面试官非常喜欢的考点。这些知识点不能只背概念一定要能做为什么游戏开发需要它的关联。西山居这种做大型MMO的公司渲染线程、逻辑线程、网络线程并发工作内存管理和对象生命周期几乎刻在每一行代码里所以笔试反复考这些完全在情理之中。3.2 一道图的遍历题从读题到最优解的思考链路笔试编程题中给我印象最深的是一道被包装成游戏场景的图论题。题目大意是一张游戏地图有许多据点据点之间有道路连接每条道路的通行时间不同。玩家要从起点据点出发到达终点据点但部分道路因为怪物封锁暂时不能走。求玩家到达终点的最短时间。剥开包装这是一道标准的单源最短路径问题。但在考场环境下完整的思考链路应该是这样第一步先判断数据规模和起终点数量。如果只有几百个据点Floyd-Warshall也能过但更好的是Dijkstra。如果起终点只有一对直接Dijkstra如果有多组查询可以考虑预处理或者Floyd。第二步考虑封锁道路。封锁道路在图论中就是边的失效。这是最容易踩坑的地方——如果你在Dijkstra过程中动态调整边权堆中存储的旧距离可能失效需要专门的失效处理。更稳的方法是在初始化时就把不可用的边排除掉不加入邻接表。如果封锁是动态的可以把不可通行的时间区间记录在边上做带时间窗的最短路径但这通常不是笔试难度。第三步选择数据结构。用C的话优先队列加邻接表是标准做法。堆中存pair当前距离节点编号每次取出当前最小距离的点松弛它的邻接边。注意pair在C中比较时是先比较first再比较second所以用距离做first即可。我给出的解法核心如下typedef pairint, int pii; // (distance, node) vectorint dijkstra(int n, int start, const vectorvectorpii graph) { vectorint dist(n, INT_MAX); dist[start] 0; priority_queuepii, vectorpii, greaterpii pq; pq.push({0, start}); while (!pq.empty()) { auto [d, u] pq.top(); pq.pop(); if (d dist[u]) continue; // 堆中的旧数据跳过 for (auto [v, w] : graph[u]) { if (dist[u] w dist[v]) { dist[v] dist[u] w; pq.push({dist[v], v}); } } } return dist; }这段代码里有两个细节值得留意一是if (d dist[u]) continue;这一行这是Dijkstra用优先队列时的经典剪枝不写的话虽然结果可能不错但堆中会积压大量过期节点浪费时间和内存二是把边信息直接存成pairint, int在笔试环境下简单清晰比自定义struct更方便。提示笔试时如果时间紧张优先保证用Dijkstra能过所有测试用例而不是去优化SPFA或者A*。A*虽然更快但需要设计启发函数在考场上风险更高除非你训练过很多次否则别轻易用。3.3 刷题优先级把力扣题单和游戏开发对齐如果准备时间有限我不建议你按照力扣热题100的顺序从头刷到尾。你可以按下面这个优先级来安排优先级考点力扣高频题类型为什么游戏开发岗重视高最短路径Dijkstra、Floyd寻路、地图、AOI场景的基础高并查集判定连通块数量技能范围、区域划分、服务器分线高二叉堆TopK、优先队列战斗中的目标选取、AI决策排序中动态规划背包、状态压缩背包系统、养成系统数值计算中二分查找答案二分、分数规划伤害计算、匹配系统、雷达范围中哈希表/字典空间换时间道具索引、NPC索引、对象池查找低字符串算法KMP、Trie文本配置表、技能名匹配、聊天系统这不是说冷门算法不重要而是从投入产出比来看上述这些高频考点覆盖了游戏开发中最常见的场景。如果你刷了两百道题还没碰到过并查集和Dijkstra那效率确实有点低建议有针对性地补一补这两个专题。4. 图形学与引擎基础背了就能拿分的常青考点图形学基础是游戏开发岗笔试区别于普通软件岗笔试的标志性内容。这部分其实不需要你真正用OpenGL写过一个渲染器只要把核心概念和它们在真实渲染管线中的位置搞清楚就能拿到大部分分数。4.1 数学与渲染基础坐标系、矩阵、渲染管线图形学的核心是数学。笔试最常考的数学概念包括齐次坐标为什么三维空间中的点要用四维坐标表示因为平移变换不能用3x3矩阵表示加一个维度后平移、旋转、缩放可以统一用矩阵乘法实现。MVP矩阵顶点从模型局部坐标Model经过模型矩阵变换到世界坐标World再经过视图矩阵变换到观察坐标View最后经过投影矩阵变换到裁剪坐标Clip。你只需要记住每个矩阵的职责考试就够用了。渲染管线阶段从顶点着色器到光栅化再到片元着色器然后经过深度测试、模板测试、混合最后输出到帧缓冲。笔试中常问一个三角形从CPU到屏幕经历了哪些阶段这就是标准答案。这些概念听起来抽象但你只要玩游戏就能找到对照你操控的角色站在场景中它的位置是局部坐标当它走过一座桥位置在世界坐标中变化你屏幕上的画面是摄像机观察的结果这是观察坐标最终显示在2D屏幕上的像素是经过了投影变换和光栅化的结果。4.2 引擎生命周期与场景管理Unity和Unreal的底层逻辑引擎相关的选择题非常直白基本就是在考生命周期和对象管理。Unity的脚本生命周期几乎是必背内容Awake在对象创建时被调用OnEnable在对象启用时调用Start在第一次Update之前调用FixedUpdate以固定时间步长调用适合物理计算Update每帧调用适合逻辑更新LateUpdate在Update之后调用适合相机跟随。笔试会故意在FixedUpdate和Update之间做文章比如刚体运动相关逻辑应该放在哪个函数里答案就是FixedUpdate因为物理引擎的步长是固定的放在Update里会导致物理模拟不稳定。对象池也是游戏开发笔试的老熟客。为什么需要对象池因为频繁Instantiate和Destroy会产生内存碎片也会触发GC导致渲染卡顿。对象池的思想是预先创建一批对象使用的时候从池中取出用完归还而不是销毁。把这个思想写成C代码核心就是内存块的复用。4.3 把知识点串起来答题怎么说才显得你是真懂别背结论你要把结论背后的因果链讲出来。比如选择题问你场景中大量对象连续创建和销毁会导致什么问题你不仅要知道答案是内存碎片和GC压力还要理解连续创建和销毁会产生大小不一的空闲内存块新对象因为找不到连续内存块而触发更大规模的内存整理这个整理过程会打断渲染线程。能把因果链讲清楚哪怕题目换个说法你也能答对。笔试中遇到这类问题我的表达策略是先说结论再补一句机制最后提一个工程上的应对。比如对象池可以解决这个问题Unity中可以用Stack存储闲置对象配合预制体和协程做预热加载。5. 笔试现场的答题策略与时间管理知识储备是底线但能不能在有限时间内把储备兑现成分数靠的是现场策略。这一节分享我经过验证的做卷顺序和时间分配方法。5.1 做卷顺序先扫选择题再啃编程题最后留时间给设计题我的建议是先花15到20分钟把选择题快速过一遍然后立刻做编程题最后留出大块时间处理游戏逻辑设计题。为什么是这个顺序选择题考察的是知识覆盖面每一题都是独立的不依赖其他题目的进展。快速扫一遍会做的直接选不会的标记一下先跳过这样能保证你在状态最好的时候拿到基础分。编程题需要读题、分析、编码是全场最耗时的环节必须在时间充裕时做避免快到交卷了才草草写两行。游戏逻辑设计题虽然分高但它不需要精确的代码细节主要靠思路即使最后剩下二十分钟也能写出有价值的文字说明。5.2 编程题的提交策略先暴力再优化在线笔试的判题系统是按测试用例给分的。这意味着你完全可以用逐步踩分的思路来答题先写一个暴力解法确保能过最小规模的数据。用示例测试用例自测一下确认输入输出格式完全正确。再在暴力解法的基础上逐步加入优化比如把线性查找改成哈希表、把递归改成迭代、把两层循环降到一层。如果优化的版本没写完至少还有一个正确但慢的版本兜底。这种方法最重要的价值是心理层面的。很多同学拿到一道题哪怕暴力解一眼就能想出来也非要直接想最优解结果悬在上面连暴力分都没拿到。游戏开发是一个需要不断迭代的项目流程先跑起来再优化这个思维在笔试中也完全适用。5.3 遇到不会的题写思路、写伪代码别留白编程题经常会遇到卡壳的情况。我的经验是不要干坐着。哪怕写不出完整代码也可以在答题框中写出你的解题思路、时间复杂度分析、甚至伪代码。部分在线笔试系统允许这类文本答案被人工判卷看到就算系统不认答题框里有文字也代表你具备分析问题的能力。注意如果笔试环境是白板式网页编辑器没有本地编译调试功能千万不要依赖编译器来检查语法。平时练习时就养成一次性写出接近正确的代码的习惯注意括号匹配、分号结尾、头文件包含这些细节考场上能省出大量宝贵时间。6. 复盘我踩过的坑和你可能也会踩的坑这一节算是付费内容了。笔试结束后我认真复盘了几个典型的翻车点把它们写在这里希望你在考场别踩同样的坑。6.1 在线笔试环境不熟悉白白浪费窗口期我第一次做在线笔试时系统用的是网页编辑器编译和运行在云端输入测试用例还要手动粘贴到特定输入框里。我用本地IDE习惯了结果切到网页编辑器后连头文件都忘了怎么包含。最尴尬的是我写了十分钟的代码才发现自己一直没点保存按钮。建议笔试前一定要去牛客网、力扣等平台做几次在线模拟笔试把输入输出格式、代码提交方式、自测用例的操作手感提前练熟。至少要知道如果代码编译失败能不能看到编译错误信息能不能在运行窗口输入多行测试数据。6.2 太依赖IDE调试切到白板环境慌了我的另一个坏习惯是平时写代码特别依赖IDE的断点调试和变量监视。笔试环境没有这些工具我写Dijkstra那道题时本地跑了三遍才通过测试用例但网页编辑器里我只能靠printf打日志来调试效率低了很多。现在回想平时写代码应该刻意练习一次性写对的能力先在纸上或注释里把逻辑框架写清楚再落代码。这样依赖IDE调试的习惯会在真正的面试手撕代码环节吃大亏。6.3 复习投入错位选择题花太多时间编程题练得不够我前期把大量时间花在背八股文上C的内存模型、虚函数表、进程通信背得滚瓜烂熟。但笔试真正拉开差距的其实是那两道编程题。尤其是第二道带时间窗的图状包装题我花了将近四十分钟最终还没有把边界情况处理完导致部分测试用例没通过。如果重来一次我会把复习时间分为60%刷题、30%巩固基础、10%看游戏开发相关的技术分析文章。基础知识点像是内功心法但笔试分数大头仍然是看得见的代码。这个比例更实用。6.4 游戏逻辑设计题的答题深度不够答题时我把游戏逻辑设计题当作普通主观题来答写了几句判断距离若小于攻击范围则受到伤害这种泛泛的话。考完复盘发现面试官想看到的不是一句话结论而是完整的模块拆解敌人在服务端管理还是客户端管理攻击范围的检测是每帧遍历还是空间分区多个敌人同时攻击同一个玩家时伤害结算顺序怎么定这些工程细节才是拉开分数的地方。所以遇到这类题我建议你按这个框架来组织答案需求拆分、数据结构选型、主循环整合、异常处理、可能的性能优化点。别怕写得多关键信息一步到位反而能体现出你的工程视野。最后再分享一个细节我那场笔试特别考了一个玩家中途掉线重连后如何恢复战斗状态的小问。这个问题很多人答的是存个档。但如果理解MMO架构就会想到服务端权威架构下战斗状态本来就由服务端维护重连只需要在客户端重建表现层状态、重新同步位置和血量即可。这种认知差异可能就决定了你最终能不能拿到面试邀请。希望你在准备笔试的过程中不只是刷题也多想想一个系统在真实游戏项目中是怎么被运转起来的。