game-development

Original🇺🇸 English
Translated

Game development patterns, architectures, and best practices

2installs
Added on

NPX Install

npx skill4agent add miles990/claude-software-skills game-development

Tags

Translated version includes tags in frontmatter

Game Development

Overview

Patterns and practices for building games across platforms. Covers architecture, rendering, physics, AI, multiplayer, and optimization.

Game Architecture

Game Loop

┌─────────────────────────────────────────────────────────────┐
│                      Game Loop                              │
│                                                             │
│   ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐ │
│   │  Input  │ ─→ │ Update  │ ─→ │ Physics │ ─→ │ Render  │ │
│   │ Process │    │  Logic  │    │  Step   │    │  Frame  │ │
│   └─────────┘    └─────────┘    └─────────┘    └─────────┘ │
│        ↑                                             │      │
│        └─────────────────────────────────────────────┘      │
│                        Next Frame                           │
└─────────────────────────────────────────────────────────────┘

Fixed vs Variable Timestep

TypeUse CaseCode Pattern
FixedPhysics, determinism
while (accumulator >= dt) { update(dt); }
VariableRendering, animations
update(deltaTime);
HybridMost gamesFixed 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);
}

Entity Component System (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;
    }
  }
}

2D Game Development

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];
  }
}

Collision Detection

MethodComplexityUse Case
AABBO(n²) → O(n log n)Boxes, simple shapes
CircleO(n²)Projectiles, characters
SATO(n²)Complex convex polygons
Pixel PerfectExpensivePrecise 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;
  }
}

Game AI

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() {}
}

Behavior Trees

┌─────────────────────────────────────────────────────────────┐
│                    Behavior Tree                            │
│                                                             │
│                      [Selector]                             │
│                     /          \                            │
│              [Sequence]      [Patrol]                       │
│              /        \                                     │
│        [CanSee?]    [Attack]                               │
│            │                                                │
│         [Chase]                                             │
└─────────────────────────────────────────────────────────────┘

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
}

Multiplayer Games

Network Architecture

ModelLatencyComplexityUse Case
Peer-to-PeerLowMediumFighting games, small lobbies
Client-ServerMediumHighMost online games
Authoritative ServerHigherHighestCompetitive games

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);
    }
  }
}

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 };
}

Game Optimization

Rendering Optimization

TechniqueBenefitImplementation
BatchingReduce draw callsCombine sprites with same texture
CullingSkip invisible objectsFrustum culling, occlusion culling
LODReduce polygon countDistance-based model switching
InstancingEfficient duplicatesGPU instancing for repeated objects

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);
}

Game Engines Reference

EngineLanguageBest ForPlatformSkill
UnityC#Mobile, indie, VRAll-
UnrealC++, BlueprintAAA, realisticPC, Console-
GodotGDScript, C#Indie, 2DAll-
FlameDartFlutter 2D, casualAllflame/
PhaserJavaScriptWeb 2DBrowser-
Three.jsJavaScriptWeb 3DBrowser-
BevyRustPerformanceDesktop-
LÖVELuaSimple 2DDesktop-

Flame Engine (Flutter)

專為 Flutter 開發者設計的 2D 遊戲引擎,詳細文件請參考 flame/SKILL.md
  • flame-core/ - 組件、輸入、碰撞、相機、動畫、音效、粒子
  • flame-systems/ - 14 個遊戲系統(任務、對話、背包、戰鬥等)
  • flame-templates/ - RPG、Platformer、Roguelike 模板

Related Skills

  • [[performance-optimization]] - General optimization
  • [[realtime-systems]] - WebSocket, networking
  • [[cpp]] - Performance-critical code
  • [[javascript-typescript]] - Web games