mcpField
G
game-code-review

game-code-review

github.com/alterlab-ieu测试与质量5081 次安装30 周前更新
代码仓库

关于 game-code-review

面向游戏开发者的代码审查工作流,同时检查通用代码质量与游戏特有的正确性和运行时风险。它涵盖帧率独立性、热路径性能、状态管理及资源清理等审查重点。

主要功能

  1. 01审查架构与依赖关系
  2. 02检查 Delta Time 与帧率独立性
  3. 03识别每帧热路径分配
  4. 04检查状态机与资源清理
  5. 05审查数据驱动值和输入处理
  6. 06检查并发与 AI 生成代码问题

适用场景

  1. 01合并重要功能分支前审查代码
  2. 02排查帧率下降等性能问题
  3. 03将原型代码转为生产代码
  4. 04为新成员说明代码质量标准

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alterlab-ieu/alterlab_gameforge --skill game-code-review

安装后在 Claude Code 中输入/game-code-review确认已加载。

详细介绍

AlterLab GameForge——游戏代码审查工作流

游戏代码有一些 Web 代码不会遇到的故障模式。Web 应用在请求处理程序中分配内存,只会增加一些延迟;游戏在更新循环中分配内存,则会造成玩家能切身感受到的掉帧。Web 应用出现状态管理错误,会显示过期数据;游戏出现状态管理错误,则可能让玩家穿墙或发射看不见的子弹。Celeste 的代码库之所以享有盛誉,正是因为 Maddy Thorson 和 Noel Berry 将帧级精准的输入处理视为首要工程问题——最终打造出了有史以来手感最出色的平台游戏。

此工作流从两个视角同时审查游戏代码:标准软件质量(命名、结构、测试、文档)和游戏特有的正确性(帧率无关性、热点路径性能、状态机完整性、资源生命周期)。两个视角都很重要。Factorio 能以 60fps 维持百万级实体模拟,是因为 Wube Software 将架构视为游戏玩法的一部分。忽视任一视角,都会导致代码要么结构良好却在运行时出错,要么性能出色却难以维护。

用途与触发条件

在以下情况下使用此工作流:

  • 开发者要求“审查我的游戏代码”或“检查我的架构”
  • 合并重要功能分支之前
  • 调试性能问题并怀疑其由结构性原因导致时
  • 新开发者加入,需要了解代码质量标准时
  • 原型开发结束后,决定哪些代码应提升至生产环境时
  • 从原型过渡到生产级代码库时

此工作流可解决的问题:

  • 无人察觉的逐帧内存分配导致帧率下降
  • 物理效果在 30fps、60fps 和 144fps 下表现不同
  • 状态机在边缘条件下进入不可能的状态
  • 场景切换时资源泄漏,导致内存逐渐增长
  • 硬编码的游戏玩法数值需要重新编译才能调整
  • 循环依赖导致系统无法单独测试
  • 原始输入处理逻辑散布在游戏玩法代码中,而未经过抽象
关键规则
  1. 优先检查游戏特有问题。 代码质量固然重要,但游戏特有问题更难诊断。违反命名规范令人烦恼;依赖帧率的物理计算则会成为已发布游戏中的错误,除开发者的机器外,在所有硬件配置上都会出现。

  2. 根据上下文判断严重程度。 在菜单界面处理程序中分配一个 new 对象没有问题;在每帧粒子更新中进行同样的分配,则会造成严重的 GC 压力。评估严重程度前,务必先考虑代码的运行位置。

  3. 以测量为准,不要猜测。 没有证据时,不要指出假设性的性能问题。如果某处看起来开销很大,应标注为“潜在问题——优化前先进行性能分析”。过早优化确实存在,过早担忧优化也一样。

  4. 引擎惯用法很重要。 每款引擎都有自己的惯例。Godot 信号不同于 Unity 事件,也不同于 Unreal 委托。应根据代码所用引擎的惯例进行审查,而不是依据抽象理想。Nolla Games 编写 Noita 时充分发挥了引擎的优势,而不是与其架构对抗,这正是其像素物理系统能够奏效的原因。针对引擎特有标准,请参考相应的引擎专家技能。

  5. 游戏玩法数值应放在数据中,而不是代码里。 设计师可能想要调整的任何数值(伤害、速度、冷却时间、生成速率、掉落概率)都必须存放在配置文件或数据表中,而不能作为常量写在源代码里。这一点不容妥协,是 docs/collaboration-protocol.md 中记载的游戏架构基本要求。

  6. 测试难以测试的内容。 游戏系统出了名地难以进行单元测试。即便如此,也应坚持采用可测试的架构。如果某个系统因为与引擎紧密耦合而无法测试,这种耦合就是值得指出的设计异味。Factorio 的开发者通过将游戏逻辑与渲染分离,为其模拟层维护了全面的自动化测试;正是这种分离让他们能够自信地发布游戏。

工作流

步骤 1:架构概览

阅读单个文件之前,先了解代码库的整体结构。

  • 梳理主要系统(渲染、物理、游戏玩法、AI、UI、音频、输入、网络)
  • 确定系统之间的依赖关系图
  • 检查是否采用了清晰的架构模式(ECS、基于组件、场景树、MVC 变体)
  • 注意游戏玩法与引擎之间是否存在抽象层
ARCHITECTURE MAP TEMPLATE
-------------------------------------------------
System            | Location          | Dependencies       | Abstracted?
-------------------------------------------------
Game Loop / Core  | [path]            | [all systems]      | Y/N
Player Controller | [path]            | Input, Physics     | Y/N
Enemy AI          | [path]            | Pathfinding, State | Y/N
UI System         | [path]            | Game State         | Y/N
Audio Manager     | [path]            | Events             | Y/N
Save System       | [path]            | Serialization      | Y/N
-------------------------------------------------

步骤 2:游戏专属代码检查

这些检查项将游戏代码审查与通用代码审查区分开来。 每项检查都针对实时交互软件中特有的一种故障模式。

检查 2.1 -- Delta Time 的使用

所有依赖时间的计算都必须使用 delta time(自上一帧经过的时间)。如果不使用 delta time,游戏行为就会随帧率而变化。

DELTA TIME AUDIT
-------------------------------------------------
FIND: Any += or -= in update/process/tick functions without * delta
FLAG: position += speed (WRONG: frame-rate dependent)
FIX:  position += speed * delta_time (CORRECT: frame-rate independent)

Also check:
- Timers that count frames instead of elapsed time
- Animation speed tied to frame rate
- Cooldowns that expire faster on faster machines
- Velocity calculations that assume fixed frame rate

Severity: CRITICAL when found in gameplay-affecting code
          MINOR when found in cosmetic-only code (particle trails, etc.)
-------------------------------------------------

检查 2.2 -- 热路径分配

每帧都会运行的代码不得分配堆内存。垃圾回收器最终会回收这些内存,但 GC 暂停会导致明显的掉帧。

HOT PATH ALLOCATION AUDIT
-------------------------------------------------
FIND: new, Array(), Object.create(), .push() growing arrays, string
      concatenation, closures capturing variables, lambda creation --
      in any function called per-frame

FLAG: Allocations in update(), _process(), _physics_process(), Tick(),
      FixedUpdate(), any function called from the main loop

FIX:  Object pooling, pre-allocated arrays, cached references,
      struct-based data (for engines that support it)

Also check:
- Dictionary/Map creation inside loops
- Temporary vector/matrix objects in physics calculations
- String formatting for debug output left in production code
- LINQ queries or functional chain calls in hot paths (C# / Unity)

Severity: CRITICAL in physics or rendering code
          MAJOR in gameplay update code
          MINOR in low-frequency systems (menu transitions, save games)
-------------------------------------------------

检查 2.3 -- 状态管理

游戏对象通常具有复杂的状态(闲置、奔跑、跳跃、攻击、受击、死亡中、已死亡)。状态管理不当是游戏中视觉故障和逻辑错误的首要来源。

STATE MANAGEMENT AUDIT
-------------------------------------------------
FIND: Boolean flags controlling behavior (is_jumping, is_attacking, can_move)
FLAG: "Boolean soup" -- multiple booleans that create implicit state combinations,
      some of which are invalid (is_jumping AND is_dead should be impossible)

PREFER: Explicit state machines with defined transitions
  - Enum-based states with switch/match statements
  - State pattern with enter/exit/update per state
  - Hierarchical state machines for complex characters

Also check:
- Can the object enter an invalid state combination?
- Are state transitions guarded (can only go from A to B, not A to D)?
- Is state entry/exit cleanup handled (stop animation on state exit)?
- Are states visualizable for debugging (can you see current state in editor)?

Severity: CRITICAL when state bugs cause gameplay-breaking behavior
          MAJOR when state bugs cause visual glitches
          MINOR when state management works but is hard to extend
-------------------------------------------------

检查 2.4 -- 帧率独立性

物理模拟必须以固定时间步长运行。渲染可以按可变帧率运行。将两者混用会导致游戏行为随硬件而变化。

FRAME-RATE INDEPENDENCE AUDIT
-------------------------------------------------
FIND: Physics calculations in variable-rate update functions
FLAG: Movement, collision, force application in Update() instead of
      FixedUpdate() (Unity) or _process() instead of _physics_process() (Godot)

Also check:
- Is the fixed timestep actually fixed, or is it accidentally variable?
- Are interpolation/extrapolation used for smooth rendering between physics steps?
- Do input-driven actions respect the physics timestep boundary?
- Are animation events synchronized with physics or rendering?

Severity: CRITICAL -- frame-rate dependent physics is always a shipped bug
-------------------------------------------------

检查 2.5 -- 资源清理

场景切换、关卡加载和重生都是内存泄漏的高发区。每项获取的资源都必须释放。

RESOURCE CLEANUP AUDIT
-------------------------------------------------
CHECK: Scene/level transition code
- Are all dynamic objects properly freed/destroyed?
- Are event listeners/signals disconnected?
- Are audio sources stopped and released?
- Are particle systems stopped before their parent is destroyed?
- Are async operations cancelled or properly awaited?
- Are pooled objects returned to pools?

CHECK: Object lifecycle
- Do spawned objects have a corresponding despawn path?
- Are references cleared when objects are destroyed?
- Are weak references used where appropriate?

Severity: MAJOR -- resource leaks cause gradual performance degradation
          CRITICAL -- if leaks cause crashes during extended play sessions
-------------------------------------------------

检查 2.6 -- 依赖方向

系统应依赖抽象,而不是具体实现。循环依赖会使系统难以测试,也难以修改。

DEPENDENCY DIRECTION AUDIT
-------------------------------------------------
CHECK: Do high-level systems (gameplay) depend on low-level systems (rendering)?
       This is fine. The reverse is a red flag.
CHECK: Do peer systems reference each other directly?
       Use events, signals, or a mediator pattern instead.
CHECK: Can you instantiate a system in a test without bringing up the entire game?
       If not, coupling is too tight.

FLAG: Circular dependencies (A depends on B depends on A)
FLAG: God objects that everything references (GameManager with 50 public fields)
FLAG: Direct references to singletons scattered throughout gameplay code

Severity: MAJOR -- architectural coupling compounds over time
-------------------------------------------------

检查 2.7 -- 数据驱动的数值

游戏玩法相关数值必须存放在数据文件中,而不是源代码中。

DATA-DRIVEN AUDIT
-------------------------------------------------
FIND: Hardcoded numeric literals in gameplay code
FLAG: speed = 5.0, damage = 10, cooldown = 0.5, spawnRate = 3
FIX:  Load from JSON, XML, CSV, or engine-native resource files

Why this matters:
- Designers cannot tune values without programmer intervention
- A/B testing requires code changes instead of config changes
- Balancing requires recompilation instead of data edits
- Platform-specific tuning (mobile vs. desktop) becomes a code branch

Exception: Mathematical constants (PI, gravity constant) and engine
configuration (target FPS, physics substeps) can be hardcoded with
a comment explaining why.

Severity: MAJOR for player-facing values (damage, speed, etc.)
          MINOR for internal system values (pool sizes, buffer lengths)
-------------------------------------------------

检查 2.8 -- 输入处理

输入应经过抽象层传递,而不是在游戏玩法代码中直接读取。

INPUT HANDLING AUDIT
-------------------------------------------------
FLAG: Direct keyboard/mouse/gamepad checks in gameplay code
      (Input.GetKey, Input.is_action_pressed without action mapping)
FLAG: Hardcoded key bindings (KeyCode.Space, KEY_W)
FLAG: Mouse/touch handling that assumes a specific screen resolution

PREFER:
- Input action maps that players can remap
- Input abstraction that translates raw input to game actions
- Context-sensitive input (same button does different things based on state)
- Input buffering for action games (queue inputs during animations)

Severity: MAJOR for shipping products (accessibility and user experience)
          MINOR for prototypes (acceptable to defer)
-------------------------------------------------

检查 2.9 -- 并发安全

如果游戏使用线程(音频、网络、资源加载),则必须保护共享状态。

CONCURRENCY AUDIT
-------------------------------------------------
CHECK: Is game state accessed from multiple threads?
CHECK: Are async operations properly synchronized?
CHECK: Is there a clear thread ownership model (which thread owns which data)?
FLAG:  Shared mutable state without locks or atomic operations
FLAG:  Race conditions in network code (state update vs. render)
FLAG:  Callback chains that assume execution order

Severity: CRITICAL when concurrency bugs cause crashes or data corruption
          MAJOR when they cause visual glitches or desync
-------------------------------------------------

检查 2.10 -- AI 生成代码的反模式

随着 AI 辅助代码生成成为标准做法,游戏代码库中越来越常出现 AI 生成的代码,并引入一类特定的错误。这些反模式不同于人工编写代码中的错误,因为它们往往看似合理,实则存在微妙的问题。

AI CODE ANTI-PATTERN AUDIT
-------------------------------------------------
CHECK 2.10.1 -- Hallucinated APIs:
  Verify that EVERY API call, method, property, and enum value referenced in
  the code actually exists in the current engine version. AI models frequently
  generate calls to APIs that existed in older versions, exist only in a
  different engine, or never existed at all.

  FLAG: Any API call that does not appear in the engine's official documentation
        for the project's engine version.
  FLAG: Method signatures that do not match the current API (wrong parameter
        count, wrong parameter types, wrong return type).
  FLAG: Enum values that do not exist in the current engine version.

  Severity: CRITICAL -- hallucinated APIs cause compile errors at best,
            silent runtime failures at worst.

CHECK 2.10.2 -- Engine-Specific Pattern Violations:
  AI models often generate code that follows generic programming patterns
  rather than engine-specific idioms. Check against `@docs/coding-standards.md`
  engine version table.

  FLAG: Using generic design patterns where the engine provides a built-in
        solution (e.g., hand-rolling an observer pattern in Godot when signals
        exist, implementing a custom coroutine system in Unity when UniTask or
        native coroutines are available).
  FLAG: Anti-patterns for the specific engine (e.g., using GetComponent() in
        Update() in Unity, using get_node() with long paths in Godot hot loops).
  FLAG: Version-specific API usage -- code written for engine version X running
        on engine version Y.

  Severity: MAJOR -- pattern violations cause maintenance burden and potential
            performance issues.

CHECK 2.10.3 -- License Compliance:
  AI-generated code can reproduce copyrighted patterns, licensed algorithms,
  or proprietary API wrappers from its training data.

  FLAG: Code blocks that appear to be direct reproductions of copyrighted
        source code (exact variable names, exact comment text, identical
        structure to known open-source implementations).
  FLAG: Algorithm implementations that match patented methods without license.
  FLAG: Middleware or SDK wrapper code that bypasses licensing requirements.

  Severity: MAJOR -- license violations create legal liability.

CHECK 2.10.4 -- Attribution:
  Document AI-assisted code sections per the project's AI usage policy.

  FLAG: Significant code blocks generated by AI without attribution comments
        indicating AI assistance.
  FLAG: Missing documentation of which AI tool was used, when, and what prompt
        produced the code.

  Follow the project's AI content policy (reference `@templates/ai-content-policy.md`
  if available). At minimum, add a comment indicating AI-assisted generation for
  any function or class substantially produced by AI tools.

  Severity: MINOR -- attribution is a process issue, not a runtime issue, but
            is important for audit trails and legal compliance.
-------------------------------------------------

检查 2.11 -- 魔法数字

每个数值常量都应有名称,最好还附有注释,说明选用该数值的设计依据。

MAGIC NUMBER AUDIT
-------------------------------------------------
FLAG: Unnamed numeric literals in any context
BAD:  if velocity.y > 4.5:    # what is 4.5? why 4.5?
GOOD: if velocity.y > TERMINAL_VELOCITY:
      # TERMINAL_VELOCITY = 4.5 -- chosen to match the visual free-fall
      # animation length (0.6s at 60fps). Tuned via playtest session #3.

The comment matters as much as the name. "SPEED = 5" tells you the name.
"SPEED = 5 -- matched to feel responsive on 1920x1080 at 60fps, may need
 scaling for other resolutions" tells you the reasoning.

Severity: MINOR individually, but accumulated magic numbers become MAJOR
          (a codebase full of unexplained numbers is a codebase nobody can tune)
-------------------------------------------------

步骤 3:标准代码质量检查

完成游戏专属检查后,再审查标准软件质量。

  • 命名规范:是否一致?是否遵循引擎规范?
  • 代码组织:文件和目录结构是否合理?
  • 错误处理:是否处理了失败情况,还是会在不报错的情况下崩溃?
  • 文档:公共 API 是否有注释?复杂算法是否有说明?
  • 测试覆盖率:游戏玩法系统是否经过测试?测试策略是什么?
  • 代码重复:是否存在大量应当抽取的复制粘贴代码?
  • 死代码:是否有未使用的函数、类或已注释掉的代码块?
输出格式
# Game Code Review Report
**Project:** [name]
**Engine:** [detected engine]
**Reviewer:** GameForge Code Review
**Date:** [date]
**Files Reviewed:** [count]

## Summary
[2-3 sentences: overall code health, top concern, biggest strength]

## Game-Specific Findings

### Critical
- **[GS-CRIT-01]** [Title] -- [file:line]
  [Description of the issue, why it matters for gameplay, and fix suggestion]

### Major
- **[GS-MAJ-01]** [Title] -- [file:line]
  [Description and fix suggestion]

### Minor
- **[GS-MIN-01]** [Title] -- [file:line]
  [Description and fix suggestion]

## Standard Quality Findings
[Same severity structure for non-game-specific issues]

## Architecture Assessment
[Dependency map, coupling analysis, pattern evaluation]

## Positive Highlights
[What the code does well -- always acknowledge good work]

## Recommended Actions
1. [Highest priority fix with estimated effort]
2. [Second priority]
3. [Third priority]
质量标准

成功的游戏代码审查需满足以下所有要求:

  • 每条发现都包含具体的文件和行号引用
  • 优先检查游戏特有的问题,而非风格问题
  • 严重性评级应反映对实际游戏体验的影响,而非理论上的完美性
  • 审查应区分原型代码(可以接受捷径)和生产代码(不应采用捷径)
  • 性能问题应标记为“先进行性能分析”,而不是直接假定存在问题
  • 应用引擎特定的惯例,而非通用的语言建议
  • 架构评估应指出风险最高的耦合点
  • 应指出良好的模式,以强化良好实践
  • 建议应按投入产出比排序

MCP 集成

代码审查工作流通过 MCP 服务连接版本控制集成和引擎专属实时代码分析,从而能够针对真实的 PR 差异进行审查,并实时根据引擎文档验证代码。

已连接的 MCP 服务
MCP 服务代码审查用途帮助方式
GitHub(已连接)PR 集成、差异分析获取 PR 差异以进行有针对性的审查;结合上下文读取变更文件;发布带有具体行号引用的审查评论;在审查前检查 CI 状态和测试结果;验证是否满足分支保护规则
Context7(已连接)验证引擎文档审查代码中是否存在虚构的 API(检查 2.10.1)时,查询 Context7 获取引擎当前文档,验证每个 API 调用、方法和枚举是否确实存在于项目所用的引擎版本中
引擎 MCP(按项目安装)实时代码分析连接相应的引擎 MCP,在运行中的编辑器中验证代码行为:
- Coding-Solo/godot-mcp(2,616 颗星)Godot 代码验证在编辑器中运行 GDScript,以验证增量时间行为、测试信号连接、检查场景树结构
- CoplayDev/unity-mcp(7,540 颗星)Unity 代码验证检查 Unity 编辑器状态、验证组件引用、检查资源依赖项
- chongdashu/unreal-mcp(1,637 颗星)Unreal 代码验证控制 Unreal Editor 以测试 Blueprint 连接、验证 C++ 编译、检查 Actor 层级结构
示例工作流

基于 PR 的代码审查:

  1. 使用 GitHub MCP 获取 PR 差异和变更文件列表
  2. 使用 Filesystem 工具读取每个变更文件
  3. 针对变更代码运行全部 11 项游戏特有检查(增量时间、热路径分配、状态管理等)
  4. 使用 Context7,根据引擎当前文档验证任何不熟悉的 API 调用
  5. 在 GitHub PR 中发布审查结果作为评论,并附上内联代码引用和严重性评级

引擎辅助的实时审查:

  1. 为项目连接相应的引擎 MCP(Godot、Unity 或 Unreal)
  2. 对于疑似存在性能问题的代码,使用引擎 MCP 在编辑器中运行代码并观察帧耗时
  3. 对于状态管理问题,使用引擎 MCP 检查游戏运行过程中对象的运行时状态
  4. 在审查报告中列出经引擎验证的发现,并附上静态分析结果
示例用例
  1. “审查我的玩家控制器代码。” 重点检查增量时间的使用、状态管理、输入处理和帧率独立性。这是玩家控制器最重要的四项检查。

  2. “战斗中出现掉帧了。你能找到原因吗?” 重点检查战斗系统中的热点路径分配、对象池和资源清理。每项发现都应附上性能分析建议。

  3. “我们即将把原型推向生产环境。需要做哪些改动?” 全面审查,重点关注数据驱动的值、依赖方向和资源清理。在测试阶段可以接受的原型捷径,到了生产环境就会成为技术债务。

  4. “有位新开发者即将加入。先帮我整理一下代码。” 重点检查命名规范、文档、魔法数字和架构评估。目标是让新加入的人能够轻松了解代码库。

  5. “我们的游戏在队友的电脑上表现不一样。” 帧率独立性和增量时间是首要怀疑对象。还要检查硬编码的屏幕分辨率、特定平台的假设,以及依赖时间的逻辑。

评论

支持 Markdown