Capítulo 817 de 859

Chapter 817: Making a Game (Manual)

Core Idea

Three.js is a rendering library, not a game engine — building a game on top of it means adding your own systems for loading/animating multiple models, organizing game logic (e.g. an Entity Component System), and sequencing time-based behavior (e.g. coroutines).

Key Concepts

  • Not a game engine: three.js gives you a scene graph and rendering, but no collision detection, physics, input handling, or pathfinding — those are the application's responsibility.
  • LoadingManager: coordinates loading multiple models via shared onProgress/onLoad callbacks so the game can wait for everything before starting and show a progress bar.
  • SkeletonUtils.clone: clones an animated/skinned glTF scene properly so multiple independent instances of the same character can be created and animated separately.
  • AnimationMixer + AnimationAction per instance: each cloned model gets its own mixer so its animations play independently of other clones of the same asset.
  • Entity Component System: a GameObject is a thin wrapper around an Object3D plus a list of components; GameObject.update() just calls update() on each component.
  • Coroutine runner: a generator-based utility for writing sequenced, time-based logic (wait N seconds, then do X) without deeply nested callbacks.

Code Examples

function* waitSeconds(duration) {
  while (duration > 0) {
    duration -= globals.deltaTime;
    yield;
  }
}

class CoroutineRunner {
  constructor() {
    this.generatorStacks = [];
    this.addQueue = [];
    this.removeQueue = new Set();
  }
  add(generator, delay = 0) {
    const genStack = [generator];
    if (delay) genStack.push(waitSeconds(delay));
    this.addQueue.push(genStack);
  }
  // update() advances each generator stack once per frame
}
  • What it demonstrates: a generator-based coroutine runner that lets game logic "wait" across frames without callback nesting.

Key Takeaways

  1. Three.js provides rendering and a scene graph, but explicitly no collision, physics, input, or pathfinding — plan to build or import those separately.
  2. Use a LoadingManager to coordinate loading multiple models and drive a progress bar before gameplay starts.
  3. Clone animated/skinned models with SkeletonUtils.clone, not a plain object clone, so each instance can animate independently.
  4. An Entity Component System (a GameObject composed of components) is a common way to keep growing game logic organized.
  5. A generator-based coroutine runner is a clean way to write sequenced, time-based behavior across frames.

Connects To

  • GLTFLoader: the loader used to bring in the animated character/animal models.
  • AnimationMixer / AnimationAction / AnimationClip: the animation-system pieces each cloned instance needs its own copy of.