game-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGame Development
游戏开发
Overview
概述
Patterns and practices for building games across platforms. Covers architecture, rendering, physics, AI, multiplayer, and optimization.
跨平台游戏开发的模式与实践,涵盖架构、渲染、物理、AI、多人游戏及优化等内容。
Game Architecture
游戏架构
Game Loop
游戏循环(Game Loop)
┌─────────────────────────────────────────────────────────────┐
│ Game Loop │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Input │ ─→ │ Update │ ─→ │ Physics │ ─→ │ Render │ │
│ │ Process │ │ Logic │ │ Step │ │ Frame │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ↑ │ │
│ └─────────────────────────────────────────────┘ │
│ Next Frame │
└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐
│ Game Loop │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Input │ ─→ │ Update │ ─→ │ Physics │ ─→ │ Render │ │
│ │ Process │ │ Logic │ │ Step │ │ Frame │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ↑ │ │
│ └─────────────────────────────────────────────┘ │
│ Next Frame │
└─────────────────────────────────────────────────────────────┘Fixed vs Variable Timestep
固定时间步长 vs 可变时间步长(Fixed vs Variable Timestep)
| Type | Use Case | Code Pattern |
|---|---|---|
| Fixed | Physics, determinism | |
| Variable | Rendering, animations | |
| Hybrid | Most games | Fixed physics, variable render |
typescript
// Hybrid game loop
let accumulator = 0;
const FIXED_DT = 1/60;
function gameLoop(currentTime: number) {
const deltaTime = currentTime - lastTime;
accumulator += deltaTime;
// Fixed timestep for physics
while (accumulator >= FIXED_DT) {
physicsUpdate(FIXED_DT);
accumulator -= FIXED_DT;
}
// Variable timestep for rendering
const alpha = accumulator / FIXED_DT;
render(alpha); // Interpolate between states
requestAnimationFrame(gameLoop);
}| 类型 | 适用场景 | 代码模式 |
|---|---|---|
| Fixed | 物理计算、确定性 | |
| Variable | 渲染、动画 | |
| Hybrid | 大多数游戏 | 固定物理步长,可变渲染步长 |
typescript
// Hybrid game loop
let accumulator = 0;
const FIXED_DT = 1/60;
function gameLoop(currentTime: number) {
const deltaTime = currentTime - lastTime;
accumulator += deltaTime;
// Fixed timestep for physics
while (accumulator >= FIXED_DT) {
physicsUpdate(FIXED_DT);
accumulator -= FIXED_DT;
}
// Variable timestep for rendering
const alpha = accumulator / FIXED_DT;
render(alpha); // Interpolate between states
requestAnimationFrame(gameLoop);
}Entity Component System (ECS)
实体组件系统(ECS)
┌─────────────────────────────────────────────────────────────┐
│ ECS Architecture │
│ │
│ Entity: Just an ID │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 1 │ │ 2 │ │ 3 │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ Components: Pure Data │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Position │ │ Velocity │ │ Sprite │ │
│ │ x, y, z │ │ vx, vy │ │ texture │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Systems: Logic │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ MovementSystem │ │ RenderSystem │ │
│ │ Position+Vel │ │ Position+Sprite│ │
│ └────────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘typescript
// Component definitions
interface Position { x: number; y: number; }
interface Velocity { vx: number; vy: number; }
interface Sprite { texture: string; width: number; height: number; }
// System
function movementSystem(entities: Entity[], dt: number) {
for (const entity of entities) {
if (entity.has(Position) && entity.has(Velocity)) {
const pos = entity.get(Position);
const vel = entity.get(Velocity);
pos.x += vel.vx * dt;
pos.y += vel.vy * dt;
}
}
}┌─────────────────────────────────────────────────────────────┐
│ ECS Architecture │
│ │
│ Entity: Just an ID │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ 1 │ │ 2 │ │ 3 │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ Components: Pure Data │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Position │ │ Velocity │ │ Sprite │ │
│ │ x, y, z │ │ vx, vy │ │ texture │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Systems: Logic │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ MovementSystem │ │ RenderSystem │ │
│ │ Position+Vel │ │ Position+Sprite│ │
│ └────────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘typescript
// Component definitions
interface Position { x: number; y: number; }
interface Velocity { vx: number; vy: number; }
interface Sprite { texture: string; width: number; height: number; }
// System
function movementSystem(entities: Entity[], dt: number) {
for (const entity of entities) {
if (entity.has(Position) && entity.has(Velocity)) {
const pos = entity.get(Position);
const vel = entity.get(Velocity);
pos.x += vel.vx * dt;
pos.y += vel.vy * dt;
}
}
}2D Game Development
2D游戏开发
Sprite Animation
精灵动画(Sprite Animation)
typescript
interface Animation {
frames: string[]; // Texture names
frameDuration: number; // Seconds per frame
loop: boolean;
}
class AnimatedSprite {
private currentFrame = 0;
private elapsed = 0;
update(dt: number) {
this.elapsed += dt;
if (this.elapsed >= this.animation.frameDuration) {
this.elapsed = 0;
this.currentFrame++;
if (this.currentFrame >= this.animation.frames.length) {
this.currentFrame = this.animation.loop ? 0 : this.animation.frames.length - 1;
}
}
}
get texture(): string {
return this.animation.frames[this.currentFrame];
}
}typescript
interface Animation {
frames: string[]; // Texture names
frameDuration: number; // Seconds per frame
loop: boolean;
}
class AnimatedSprite {
private currentFrame = 0;
private elapsed = 0;
update(dt: number) {
this.elapsed += dt;
if (this.elapsed >= this.animation.frameDuration) {
this.elapsed = 0;
this.currentFrame++;
if (this.currentFrame >= this.animation.frames.length) {
this.currentFrame = this.animation.loop ? 0 : this.animation.frames.length - 1;
}
}
}
get texture(): string {
return this.animation.frames[this.currentFrame];
}
}Collision Detection
碰撞检测(Collision Detection)
| Method | Complexity | Use Case |
|---|---|---|
| AABB | O(n²) → O(n log n) | Boxes, simple shapes |
| Circle | O(n²) | Projectiles, characters |
| SAT | O(n²) | Complex convex polygons |
| Pixel Perfect | Expensive | Precise collision |
typescript
// AABB collision
function aabbIntersect(a: AABB, b: AABB): boolean {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
// Spatial hash for broad phase
class SpatialHash {
private cells = new Map<string, Entity[]>();
private cellSize: number;
insert(entity: Entity) {
const key = this.getKey(entity.position);
if (!this.cells.has(key)) this.cells.set(key, []);
this.cells.get(key)!.push(entity);
}
query(position: Vector2): Entity[] {
// Check neighboring cells
const nearby: Entity[] = [];
for (let dx = -1; dx <= 1; dx++) {
for (let dy = -1; dy <= 1; dy++) {
const key = this.getKey({ x: position.x + dx * this.cellSize, y: position.y + dy * this.cellSize });
nearby.push(...(this.cells.get(key) || []));
}
}
return nearby;
}
}| 方法 | 复杂度 | 适用场景 |
|---|---|---|
| AABB | O(n²) → O(n log n) | 矩形、简单形状 |
| Circle | O(n²) | 抛射物、角色 |
| SAT | O(n²) | 复杂凸多边形 |
| Pixel Perfect | 开销大 | 高精度碰撞 |
typescript
// AABB collision
function aabbIntersect(a: AABB, b: AABB): boolean {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
// Spatial hash for broad phase
class SpatialHash {
private cells = new Map<string, Entity[]>();
private cellSize: number;
insert(entity: Entity) {
const key = this.getKey(entity.position);
if (!this.cells.has(key)) this.cells.set(key, []);
this.cells.get(key)!.push(entity);
}
query(position: Vector2): Entity[] {
// Check neighboring cells
const nearby: Entity[] = [];
for (let dx = -1; dx <= 1; dx++) {
for (let dy = -1; dy <= 1; dy++) {
const key = this.getKey({ x: position.x + dx * this.cellSize, y: position.y + dy * this.cellSize });
nearby.push(...(this.cells.get(key) || []));
}
}
return nearby;
}
}Game AI
游戏AI
Finite State Machine
有限状态机(Finite State Machine)
typescript
interface State {
enter(): void;
update(dt: number): void;
exit(): void;
}
class EnemyAI {
private states = new Map<string, State>();
private currentState: State;
transition(stateName: string) {
this.currentState?.exit();
this.currentState = this.states.get(stateName)!;
this.currentState.enter();
}
}
// Example: Patrol → Chase → Attack
class PatrolState implements State {
enter() { this.setAnimation('walk'); }
update(dt: number) {
this.patrol();
if (this.canSeePlayer()) {
this.fsm.transition('chase');
}
}
exit() {}
}typescript
interface State {
enter(): void;
update(dt: number): void;
exit(): void;
}
class EnemyAI {
private states = new Map<string, State>();
private currentState: State;
transition(stateName: string) {
this.currentState?.exit();
this.currentState = this.states.get(stateName)!;
this.currentState.enter();
}
}
// Example: Patrol → Chase → Attack
class PatrolState implements State {
enter() { this.setAnimation('walk'); }
update(dt: number) {
this.patrol();
if (this.canSeePlayer()) {
this.fsm.transition('chase');
}
}
exit() {}
}Behavior Trees
行为树(Behavior Trees)
┌─────────────────────────────────────────────────────────────┐
│ Behavior Tree │
│ │
│ [Selector] │
│ / \ │
│ [Sequence] [Patrol] │
│ / \ │
│ [CanSee?] [Attack] │
│ │ │
│ [Chase] │
└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐
│ Behavior Tree │
│ │
│ [Selector] │
│ / \ │
│ [Sequence] [Patrol] │
│ / \ │
│ [CanSee?] [Attack] │
│ │ │
│ [Chase] │
└─────────────────────────────────────────────────────────────┘Pathfinding (A*)
寻路(A算法)(Pathfinding (A))
typescript
function aStar(start: Node, goal: Node): Node[] {
const openSet = new PriorityQueue<Node>();
const cameFrom = new Map<Node, Node>();
const gScore = new Map<Node, number>();
const fScore = new Map<Node, number>();
gScore.set(start, 0);
fScore.set(start, heuristic(start, goal));
openSet.enqueue(start, fScore.get(start)!);
while (!openSet.isEmpty()) {
const current = openSet.dequeue()!;
if (current === goal) {
return reconstructPath(cameFrom, current);
}
for (const neighbor of getNeighbors(current)) {
const tentativeG = gScore.get(current)! + distance(current, neighbor);
if (tentativeG < (gScore.get(neighbor) ?? Infinity)) {
cameFrom.set(neighbor, current);
gScore.set(neighbor, tentativeG);
fScore.set(neighbor, tentativeG + heuristic(neighbor, goal));
openSet.enqueue(neighbor, fScore.get(neighbor)!);
}
}
}
return []; // No path found
}typescript
function aStar(start: Node, goal: Node): Node[] {
const openSet = new PriorityQueue<Node>();
const cameFrom = new Map<Node, Node>();
const gScore = new Map<Node, number>();
const fScore = new Map<Node, number>();
gScore.set(start, 0);
fScore.set(start, heuristic(start, goal));
openSet.enqueue(start, fScore.get(start)!);
while (!openSet.isEmpty()) {
const current = openSet.dequeue()!;
if (current === goal) {
return reconstructPath(cameFrom, current);
}
for (const neighbor of getNeighbors(current)) {
const tentativeG = gScore.get(current)! + distance(current, neighbor);
if (tentativeG < (gScore.get(neighbor) ?? Infinity)) {
cameFrom.set(neighbor, current);
gScore.set(neighbor, tentativeG);
fScore.set(neighbor, tentativeG + heuristic(neighbor, goal));
openSet.enqueue(neighbor, fScore.get(neighbor)!);
}
}
}
return []; // No path found
}Multiplayer Games
多人游戏
Network Architecture
网络架构(Network Architecture)
| Model | Latency | Complexity | Use Case |
|---|---|---|---|
| Peer-to-Peer | Low | Medium | Fighting games, small lobbies |
| Client-Server | Medium | High | Most online games |
| Authoritative Server | Higher | Highest | Competitive games |
| 模型 | 延迟 | 复杂度 | 适用场景 |
|---|---|---|---|
| Peer-to-Peer | 低 | 中等 | 格斗游戏、小型房间 |
| Client-Server | 中等 | 高 | 大多数在线游戏 |
| Authoritative Server | 较高 | 最高 | 竞技类游戏 |
Lag Compensation
延迟补偿(Lag Compensation)
typescript
// Client-side prediction
class NetworkedPlayer {
private pendingInputs: Input[] = [];
private serverState: PlayerState;
update(input: Input) {
// 1. Apply input locally (prediction)
this.applyInput(input);
this.pendingInputs.push(input);
// 2. Send to server
this.sendInput(input);
}
onServerUpdate(state: PlayerState, lastProcessedInput: number) {
// 3. Reconcile with server
this.serverState = state;
// 4. Re-apply unprocessed inputs
this.pendingInputs = this.pendingInputs.filter(i => i.id > lastProcessedInput);
for (const input of this.pendingInputs) {
this.applyInput(input);
}
}
}typescript
// Client-side prediction
class NetworkedPlayer {
private pendingInputs: Input[] = [];
private serverState: PlayerState;
update(input: Input) {
// 1. Apply input locally (prediction)
this.applyInput(input);
this.pendingInputs.push(input);
// 2. Send to server
this.sendInput(input);
}
onServerUpdate(state: PlayerState, lastProcessedInput: number) {
// 3. Reconcile with server
this.serverState = state;
// 4. Re-apply unprocessed inputs
this.pendingInputs = this.pendingInputs.filter(i => i.id > lastProcessedInput);
for (const input of this.pendingInputs) {
this.applyInput(input);
}
}
}State Synchronization
状态同步(State Synchronization)
typescript
// Delta compression
interface StateDelta {
timestamp: number;
changes: Map<EntityId, ComponentChanges>;
}
function computeDelta(prev: GameState, curr: GameState): StateDelta {
const changes = new Map();
for (const [id, entity] of curr.entities) {
const prevEntity = prev.entities.get(id);
if (!prevEntity || hasChanged(prevEntity, entity)) {
changes.set(id, getChangedComponents(prevEntity, entity));
}
}
return { timestamp: curr.timestamp, changes };
}typescript
// Delta compression
interface StateDelta {
timestamp: number;
changes: Map<EntityId, ComponentChanges>;
}
function computeDelta(prev: GameState, curr: GameState): StateDelta {
const changes = new Map();
for (const [id, entity] of curr.entities) {
const prevEntity = prev.entities.get(id);
if (!prevEntity || hasChanged(prevEntity, entity)) {
changes.set(id, getChangedComponents(prevEntity, entity));
}
}
return { timestamp: curr.timestamp, changes };
}Game Optimization
游戏优化
Rendering Optimization
渲染优化(Rendering Optimization)
| Technique | Benefit | Implementation |
|---|---|---|
| Batching | Reduce draw calls | Combine sprites with same texture |
| Culling | Skip invisible objects | Frustum culling, occlusion culling |
| LOD | Reduce polygon count | Distance-based model switching |
| Instancing | Efficient duplicates | GPU instancing for repeated objects |
| 技术 | 收益 | 实现方式 |
|---|---|---|
| Batching | 减少绘制调用 | 合并相同纹理的精灵 |
| Culling | 跳过不可见对象 | 视锥体剔除、遮挡剔除 |
| LOD | 降低多边形数量 | 基于距离的模型切换 |
| Instancing | 高效渲染重复对象 | GPU实例化渲染重复物体 |
Memory Optimization
内存优化(Memory Optimization)
typescript
// Object pooling
class ObjectPool<T> {
private pool: T[] = [];
private factory: () => T;
acquire(): T {
return this.pool.pop() ?? this.factory();
}
release(obj: T) {
this.reset(obj);
this.pool.push(obj);
}
}
// Usage
const bulletPool = new ObjectPool(() => new Bullet());
function fireBullet() {
const bullet = bulletPool.acquire();
bullet.init(position, direction);
activeBullets.add(bullet);
}
function onBulletHit(bullet: Bullet) {
activeBullets.delete(bullet);
bulletPool.release(bullet);
}typescript
// Object pooling
class ObjectPool<T> {
private pool: T[] = [];
private factory: () => T;
acquire(): T {
return this.pool.pop() ?? this.factory();
}
release(obj: T) {
this.reset(obj);
this.pool.push(obj);
}
}
// Usage
const bulletPool = new ObjectPool(() => new Bullet());
function fireBullet() {
const bullet = bulletPool.acquire();
bullet.init(position, direction);
activeBullets.add(bullet);
}
function onBulletHit(bullet: Bullet) {
activeBullets.delete(bullet);
bulletPool.release(bullet);
}Game Engines Reference
游戏引擎参考
| Engine | Language | Best For | Platform | Skill |
|---|---|---|---|---|
| Unity | C# | Mobile, indie, VR | All | - |
| Unreal | C++, Blueprint | AAA, realistic | PC, Console | - |
| Godot | GDScript, C# | Indie, 2D | All | - |
| Flame | Dart | Flutter 2D, casual | All | flame/ |
| Phaser | JavaScript | Web 2D | Browser | - |
| Three.js | JavaScript | Web 3D | Browser | - |
| Bevy | Rust | Performance | Desktop | - |
| LÖVE | Lua | Simple 2D | Desktop | - |
| 引擎 | 开发语言 | 适用场景 | 平台 | 技能 |
|---|---|---|---|---|
| Unity | C# | 移动游戏、独立游戏、VR | 全平台 | - |
| Unreal | C++, Blueprint | AAA游戏、写实风格 | PC、主机 | - |
| Godot | GDScript, C# | 独立游戏、2D游戏 | 全平台 | - |
| Flame | Dart | Flutter 2D游戏、休闲游戏 | 全平台 | flame/ |
| Phaser | JavaScript | Web 2D游戏 | 浏览器 | - |
| Three.js | JavaScript | Web 3D游戏 | 浏览器 | - |
| Bevy | Rust | 高性能游戏 | 桌面端 | - |
| LÖVE | Lua | 简单2D游戏 | 桌面端 | - |
Flame Engine (Flutter)
Flame引擎(Flutter)
專為 Flutter 開發者設計的 2D 遊戲引擎,詳細文件請參考 flame/SKILL.md:
- flame-core/ - 組件、輸入、碰撞、相機、動畫、音效、粒子
- flame-systems/ - 14 個遊戲系統(任務、對話、背包、戰鬥等)
- flame-templates/ - RPG、Platformer、Roguelike 模板
专为Flutter开发者设计的2D游戏引擎,详细文档请参考 flame/SKILL.md:
- flame-core/ - 组件、输入、碰撞、相机、动画、音效、粒子
- flame-systems/ - 14个游戏系统(任务、对话、背包、战斗等)
- flame-templates/ - RPG、平台跳跃、Roguelike模板
Related Skills
相关技能
- [[performance-optimization]] - General optimization
- [[realtime-systems]] - WebSocket, networking
- [[cpp]] - Performance-critical code
- [[javascript-typescript]] - Web games
- [[performance-optimization]] - 通用优化
- [[realtime-systems]] - WebSocket、网络通信
- [[cpp]] - 性能关键代码
- [[javascript-typescript]] - Web游戏开发