游戏开发实习生笔试指南:C++、算法与渲染网络全考点

发布时间:2026/8/29 21:52:31
游戏开发实习生笔试指南:C++、算法与渲染网络全考点 去年5月26号下午我坐在畅游的笔试教室里拿到那套游戏开发实习生的题目时第一反应是这套题不像网上流传的那些“大厂刷题集”反而很像一个主程随手给你出的验收卷。整套卷子覆盖C、算法、基础图形学、物理和一点网络同步题干不算长但不少地方埋了细节稍不留神就会掉坑。如果你是准备投游戏开发实习的同学这套题值得拿来当一次“摸底考试”做因为考的不是你背了多少八股而是你在笔试现场能不能把一个工程问题拆清楚、写干净。这篇博文我就以18届这次笔试为线索把游戏开发实习生的常见考点拆开讲。不会去逐字背题而是说考点、说思路、说现场怎么避坑。你可以把它当成一份“游戏开发实习生笔试能力图谱”看完之后既能知道该往哪些方向发力也能避开我自己踩过的那些雷。1. 笔试整体观感一场筛选“工程底线”的考试1.1 题量分布与现场印象整套试卷的题量不算夸张大致是选择题、填空题、简答题、手写代码题混排。时间给得比较足但真正做完的人很少。原因很简单代码题不是让你写伪代码而是要求在白纸上写出可以编译的C代码包括头文件、边界判断、内存处理都要考虑。这个要求和LeetCode完全不一样LeetCode只要核心函数而笔试现场要的是完整思路加严谨细节。从题目类型来看C占的比重最大大概有三分之一。然后是数据结构和算法涉及链表、二叉树、排序、动态规划这类经典内容。再往后是游戏开发基础包括渲染管线、DrawCall、碰撞检测、网络同步的模型。说实话这些题单个拎出来都不算难但合在一起就变成了“压力测试”看你平时积累够不够厚能不能在有限时间里有条理地输出。我当时做题的顺序是先扫一遍全卷把简答题的分拿稳再回头死磕代码题。这种策略后来证明很有效因为简答题往往考察的是概念是否清晰只要平时看过引擎文档或图形学基础基本都能写出七七八八。代码题卡住了就先跳不要在一道题上耗二十分钟否则后面会崩盘。1.2 出题人想要什么样的人畅游是端游、手游都做的公司国内有完整的自研引擎和运维体系所以它招游戏开发实习生的时候最看重的不是你会不会用某个引擎而是有没有“工程底线”。什么是工程底线就是内存不会随便泄漏多线程不会写出数据竞争链表反转不会丢指针给一个需求能拆成模块而不是一把梭。从这套题就能看出来出题人默认你已经掌握了C的基础语法并且有实际写代码的经验。他不会问你“什么是虚函数”这种概念题而是会给一段代码问你输出结果是什么或者指出哪里会导致崩溃。所以如果你还停留在“看过《C Primer》但没写过几个类”的阶段这套题会显得很难受。反过来如果你自己做过小游戏项目写过一些组件、管理过生命周期很多题目会觉得很亲切。另外题目里还透着一个信号游戏开发实习生的日常不是天天做玩法而是先解决一堆底层问题。比如资源加载、对象池、热更新、性能瓶颈排查。笔试就是在看你能不能理解这些底层问题背后的通用原理。2. C、内存与多线程躲不掉的基本功2.1 指针、引用与内存布局C部分几乎绕不开指针和内存布局。常见的考法有两种一种是给一个结构体问你sizeof是多少为什么另一种是给一段指针操作的代码问输出或崩溃点。这两类题看起来简单实际错误率很高因为牵涉到对齐、虚表指针、引用折叠等一堆细节。我在备考过程中最常用的方法是“画内存图”。遇到指针相关的问题不要空想直接在草稿纸上画出栈、堆、全局区各自的变量然后把指针的指向用箭头标清楚。一旦把内存图画出来很多问题就豁然开朗。例如一个类里有虚函数它的实例大小就多了一个虚表指针如果是继承且重写了虚函数内存布局还要看虚基类的情况。这类题在实习笔试里很少考到特别偏的但基本规则一定要记住。另一个高频考点是“深拷贝与浅拷贝”。游戏引擎里的资源对象、组件对象经常需要拷贝如果只是浅拷贝两个对象会共享同一块堆内存析构时就会出现double free。笔试通常会拿一个字符串类或者自定义Vector类让你实现拷贝构造、赋值运算符和析构函数。我当时是直接在纸上写了一个带引用计数的String类重点在于赋值运算符要先判断自赋值再释放旧内存最后分配新内存并拷贝数据。三步缺一不可。下面是当时我练习时写过的简化版String类核心代码可以帮你快速复习这个考点class String { public: String(const char* str nullptr) { if (str nullptr) { m_data new char[1]; *m_data \0; } else { size_t len strlen(str); m_data new char[len 1]; strcpy(m_data, str); } } String(const String other) { size_t len strlen(other.m_data); m_data new char[len 1]; strcpy(m_data, other.m_data); } String operator(const String other) { if (this ! other) { delete[] m_data; size_t len strlen(other.m_data); m_data new char[len 1]; strcpy(m_data, other.m_data); } return *this; } ~String() { delete[] m_data; } private: char* m_data; };这个版本虽然还有异常安全的问题但笔试阶段已经能说明你理解了拷贝控制。如果你能把“三/五法则”讲清楚并且在代码里处理自赋值面试官对你的印象会好很多。2.2 多线程与同步问题游戏服务器和客户端引擎都有多线程场景所以笔试出现线程题我一点也不意外。常见考法是两个线程并发操作同一个全局变量问最终值范围是多少或者让你用锁、原子变量修复它。这类题考点非常集中无非是数据竞争、临界区、死锁。当时我遇到的是一个计数自增的简化模型多个线程并发执行counter问你最终结果是否等于线程数乘循环次数。答案是几乎不可能等于。原因就是counter在编译后不是原子操作读、加、写三步会被线程调度打断导致丢更新。修复方式要么加std::mutex要么用std::atomicint。笔试时我直接给出了用std::atomic的方案因为它在单变量场景下更轻量语义也更清晰。还有一类题是“如何避免死锁”。我在准备时总结了一个自己的判断口诀多个锁的加锁顺序必须全局一致能用一个锁就不用两个如果必须持有多个锁优先用std::lock一次性获取。这个口诀在笔试和面试里救过我很多次。下面是一个用std::atomic修复并发的简单示例#include atomic std::atomicint counter{0}; void worker(int n) { for (int i 0; i n; i) { counter.fetch_add(1, std::memory_order_relaxed); } }这里的memory_order_relaxed可能不是最优选择但笔试里能写出原子操作已经说明你对并发有意识了。如果面试官追问再说清楚默认的seq_cst更安全但性能可能略差就可以应付过去。2.3 常见C笔试大题示例笔试最后一道C大题通常是让你写一个“对象池”或“工厂模式”的简化实现。为什么考这个因为游戏开发里频繁创建和销毁敌人、子弹、特效如果用new和delete每次分配内存会产生大量内存碎片甚至卡顿。对象池就是预先创建一批对象用状态标记是否存活取用时找一个空闲对象归还时重置状态。写对象池有几个关键点要掌握。第一池子内部用固定数组或vector尽量避免在运行期扩容。第二对象需要有“激活/失活”标志位而不是真的析构。第三池子的遍历要考虑性能最好维护索引或空闲列表。第四归还对象要重置干净否则会出现“残留上一帧数据”的bug。我当时在纸上写了一个子弹对象池结构大概是这样的class Bullet { public: bool active; Vector3 pos; Vector3 velocity; }; class BulletPool { public: BulletPool(int capacity) { m_pool.resize(capacity); } Bullet* Get() { for (auto bullet : m_pool) { if (!bullet.active) { bullet.active true; bullet.pos Vector3::zero; bullet.velocity Vector3::zero; return bullet; } } return nullptr; } void Release(Bullet* bullet) { bullet-active false; } private: std::vectorBullet m_pool; };这个实现足够应付笔试。但你在讲解时一定要提一句“这里存在性能问题遍历所有子弹找空闲对象当池子很大时有O(n)开销。可以改成空闲列表把释放对象的索引放到队列里Get时直接取队头”。能说到这一步说明你真的考虑过工程实现而不只是背模板。3. 数据结构与算法熟练度决定上限3.1 链表类题目的“送分与陷阱”游戏开发笔试里的算法题不像ACM那么疯狂很多都是经典题型的变体比如链表反转、判断链表是否有环、合并两个有序链表。这些题目本身不难但现场手写容易翻车因为链表操作对边界极其敏感。我记得当时有一道题是“反转单链表”看起来是送分题可一旦在纸上写很多同学就在头节点的处理上卡住。写链表反转有四种常见方式迭代、递归、头插法、栈。笔试时最推荐迭代法因为它空间复杂度O(1)代码也最容易验证。核心思想就三句话保存下一个节点把当前节点的next指向前驱移动前驱和当前指针。我当时为了不出错还会先画一个3节点链表把每一步的指针变化标出来再往代码里填。另外要小心“dummy head”技巧。很多链表题比如删除倒数第K个节点、删除有序链表的重复项都可以用虚拟头节点规避掉“删除头节点”的特殊处理。这个技巧写起来很快而且能减少边界Bug。笔试时哪怕题目没有明确要求我建议也先定义ListNode* dummy new ListNode(0); dummy-next head;最后返回dummy-next这样头节点就不会额外判断。链表题的另一个高频陷阱是“是否会造成环”。举个例子很多同学在合并两个有序链表时会直接把一个链表的节点插到另一个链表里但忘记封尾结果整个链表变成一个环。这种错误在本地调试时很容易发现但在纸上笔试时很难一眼看出。所以我给自己定了一个习惯写完链表代码后从head开始顺序走一遍检查每个节点的next是否指向了不该指的对象。3.2 树与图的遍历思路树和图的题目在游戏开发笔试中也很常见因为场景管理、寻路、技能效果结算都跟树和图脱不开关系。笔试里一般不会要求写A*寻路的完整实现但会考二叉树的BFS/DFS、层序遍历、最近公共祖先这类基础题。这些题目主要考察你有没有真正理解递归和队列栈的关系。我的经验是遇到树的问题先看递归能不能解再看迭代能不能解两个方案都写一下会加分。比如“判断一棵树是否对称”递归解法是把根节点的左右子树看成两棵树同时比较外侧和内侧迭代解法则是用队列成对入队每次取出两个节点比较并保证它们的孩子也按对称顺序入队。笔试中我通常给出迭代解法因为这样能给面试官展示“我不只懂递归”。图的部分考得最多的是“判断图中两个节点是否连通”以及“拓扑排序”。前者可以用DFS或BFS后者在游戏任务依赖、技能树解锁里很实用。拓扑排序有一个模板思路先统计每个节点的入度把入度为0的节点入队每次出队一个节点把它的邻接节点入度减1如果入度变成0就继续入队。如果最终入队节点数不等于总节点数说明图里有环。这个判断环的思路在笔试里经常被用来出陷阱题。写图算法题的时候我建议把图明确存储成邻接表而不是邻接矩阵。原因有两个游戏场景里的图通常很稀疏邻接表更省内存笔试时用vectorvectorint做邻接表写起来也最快。如果题目带权可以把int扩展成pairint,int。3.3 动态规划现场怎么能不慌动态规划是很多同学最怕的算法题但游戏开发笔试里的DP通常比较基础比如最长递增子序列、背包问题、编辑距离。它不会给你一个很偏的状态方程因为你是在考“游戏开发实习生”不是在考“算法竞赛选手”。不过一旦考到DP就一定要把“状态定义、转移方程、初始化、遍历顺序”四件事说清楚。我拿到DP题的第一件事不是急着写代码而是先写状态定义和转移方程哪怕只是注释。这样就算最终代码有Bug阅卷人也能看到你的思路。比如最长递增子序列状态dp[i]表示以第i个元素结尾的最长递增子序列长度转移方程就是枚举j i如果nums[j] nums[i]就用dp[j] 1更新dp[i]。时间复杂度O(n^2)笔试完全可接受不用一上来就写二分优化。有时候笔试会出“走格子”问题比如从左上角到右下角有多少种走法或者最小路径和。这类题的状态转移其实都写在题目里了只要把边界条件处理好基本能拿满分。比较坑的是“二维数组越界”和“初始化错误”。我在备考时会把所有DP题都先画一个表格把表格的0行0列填充好再按行或按列递推这样出错的概率会低很多。如果时间充裕可以再记一记“背包问题”的滚动数组写法把二维dp压缩到一维并注意倒序遍历容量。这个技巧在笔试里很亮眼而且一旦理解了为什么倒序你就真正掌握了DP的遍历顺序不是死记硬背。4. 游戏渲染、物理与网络专业方向的试金石4.1 渲染基础状态切换与DrawCall游戏开发实习生的笔试不会让你去写一个光栅化器但会考一些渲染管线的核心概念。我记得题目里出现了“DrawCall”并问你为什么大量DrawCall会拖慢帧率以及如何优化。这个问题现在基本是游戏开发笔试必问因为它是客户端性能优化的核心。DrawCall是CPU向GPU发出的一次绘制命令。每切换一次纹理、Shader、状态GPU可能都需要重新配置渲染管线这个开销非常大。如果场景里有1000个物体每个物体都提交一次DrawCallCPU就容易被拖垮。优化思路常见有几种合批Batching、纹理图集Atlas、减少状态切换、使用GPU Instancing。笔试里最好能答出“合批是指把多个小网格合并成一个大网格一次性提交从而减少状态切换”。同时要提一句“合批不是万能的如果物体有动态动画或者不同材质合批效果会大打折扣”。有一类题还会给你一个简化场景100个怪物、50个特效、10个UI面板问你怎么估算DrawCall。我当时的方法是先算每个对象的材质种类数和网格数量再进行场景分块统计每一帧中可见的对象数量。这里要注意“视锥剔除”和“遮挡剔除”因为不可见对象不需要绘制DrawCall就会少很多。笔试中写出“先剔除再合批最后绘制”这个顺序比背数字重要得多。4.2 物理与碰撞检测物理题是游戏开发笔试的特色之一。常见考点包括AABB碰撞检测、刚体动力学概念、帧率对物理模拟的影响。AABB碰撞检测的考法通常是两个矩形或盒子分别用最小点(xmin, ymin)和最大点(xmax, ymax)表示问如何判断它们是否相交。检测规则就是判断两个矩形在x轴和y轴的投影区间是否都重叠只要一个轴不重叠就一定不相交。这个考点虽然基础但笔试时最容易漏掉“坐标轴方向”。比如Unity的屏幕坐标系和世界坐标系不一样World坐标旋转后AABB不一定还能精确表达物体形状所以大型项目里会再细分OBB或凸包碰撞。如果你能在基础代码之外补一句“AABB适合碰撞粗略检测精确检测需要更细的碰撞体”面试官会认为你有实战认知。物理模拟还有一个经典坑固定时间步长。游戏如果按帧调用物理更新帧率波动会导致物体运动速度不一致帧率很低时甚至会出现物体穿透。面试官喜欢问的解法是“用固定步长的物理流水线同时做插值渲染”。笔试里只要能把这几句话写出来就已经超过一大半考生了。4.3 网络同步的基本模型网络同步题在很多客户端笔试里会出现因为MMORPG、竞技游戏都逃不开它。畅游做过不少网游所以在笔试里考网络同步模型非常合理。常见考点是状态同步和帧同步的区别以及它们的优缺点。状态同步的特点是客户端把操作发给服务器服务器计算最终状态再广播给所有客户端。它的优点是逻辑集中在服务器好防作弊但带宽消耗高战斗打击感容易受延迟影响。帧同步的特点是每个客户端都跑同一份逻辑只同步操作指令能极大节省带宽格斗、RTS游戏常用但要求客户端逻辑完全确定性浮点误差会导致不同步。笔试里如果让你选一种模式实现一个房间内的战斗同步我会选帧同步方案并说明关键点所有随机数种子一致、所有浮点运算必须使用相同精度、逻辑帧率固定、需要定期校验hash。这些关键点才是阅卷人想看的因为大多数学生只会说“帧同步就是同步指令”而不知道落地时会踩哪些坑。网络部分有时候还会考TCP和UDP的区别游戏里为什么常用UDP。别只答“TCP可靠但慢UDP不可靠但快”。要补充一句“游戏对延迟更敏感丢失少量包可以被预测和插值弥补但延迟高会直接影响操作手感所以很多实时对战在传输层基于UDP做自定义可靠传输”。能说到这个层面网络题基本就没问题了。5. 常见失分点与实用备考建议5.1 现场最容易翻车的三类失误第一类是“只会LeetCode式写法不会完整工程代码”。笔试代码题要求的是严格包含头文件、命名空间、返回值的完整代码很多同学只写了核心逻辑结果试卷上缺头文件、缺返回值、缺边界判断白白丢分。第二类是“简答题答太短”。游戏笔试的简答题问的是“你认为如何”其实是想看你的思路链条。比如问“如何降低游戏包体大小”你不能只回答“压缩贴图”而是要从资源格式、音频码率、分包加载、动态下载等维度展开。哪怕不完全正确也要展示你考虑过多种手段。第三类是“时间分配失衡”。有人在一道C大题上死磕40分钟结果后面10道选择题都没时间做。我的策略是先把选择题和简答题全部拿下再回头写代码题。因为选择题猜对的概率也比空白高简答题只要写就有分而代码题一旦思路卡住两小时都未必能调通。5.2 给非科班同学的补课路线如果你不是计算机科班出身但想投游戏开发实习我建议按这个顺序补先花两周把C的指针、内存、拷贝控制、多线程基础过一遍不要纠结模板元编程那是高阶内容。然后刷数据结构重点是数组、链表、栈、队列、二叉树、哈希表配合LeetCode简单和中等题目练手。之后进入游戏开发基础我推荐用Unity或者Godot做一个小项目比如一个2D顶视角射击游戏。在做项目的过程中你会自然地接触到对象池、碰撞检测、动画状态机、UI管理、场景切换。这个过程比听课重要得多。很多笔试简答题只要做过项目哪怕规模很小也能写出答案。最后再回到算法题每天保证两到三题周末做一次限时模拟。笔试前两周把所有刷过的题用白纸手写一遍训练自己不用IDE也能写出规范代码。这个训练极其重要能很大程度减少笔试时的紧张感。5.3 从笔试题反推项目经验设计如果你现在还没什么项目可写不妨根据这套笔试的考点去设计两个小项目。第一个项目是“内存管理组件”做一个对象池并封装成Unity里的MonoBehaviour组件支持预热、取用和归还。第二个项目是“简易战斗同步Demo”用帧同步做两个角色移动和攻击的联机演示重点是把逻辑帧和渲染帧分开、固定时间步长、同步随机数种子。这两个项目刚好对应笔试里的C、数据结构和网络题。有了项目之后笔试前还可以把项目里遇到的问题写成一页纸包括为什么用对象池、为什么固定步长、怎么解决不同步。这些都是面试官非常爱问的内容。因为笔试考的是基础面试考的是你有没有真的做过东西。基础决定你过不过笔试项目决定你过不过面试。如果你能把上面这些点都准备到位那么面对2017年那套题也好之后的同类题目也好心态会稳很多。我当时印象最深的是不少题目并不是考“会不会”而是考“现场能不能冷静下来”。所以最后再分享一个小技巧笔试开始前五分钟先深呼吸把全卷扫一遍用铅笔在每道题旁边标上当次难度和预估用时。这样做完一遍之后你的大脑会自动进入解题状态而不是在焦虑里耗尽能量。这个技巧不起眼但我试过很多次真的能多拿不少分。