threejs-game

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Three.js Game Development Skill

Three.js游戏开发技能

Comprehensive assistance with Three.js game development using WebGL, covering 3D rendering, game mechanics, physics, animations, and interactive browser-based games.
提供使用WebGL进行Three.js游戏开发的全面支持,涵盖3D渲染、游戏机制、物理系统、动画以及基于浏览器的交互式游戏开发。

When to Use This Skill

何时使用此技能

Activate this skill when:
  • Building 3D web games with Three.js
  • Implementing game mechanics (player movement, collisions, scoring)
  • Setting up cameras, lighting, and scene management
  • Loading 3D models (GLTF, OBJ, FBX)
  • Handling user input (keyboard, mouse, touch, gamepad)
  • Creating animations and character controllers
  • Integrating physics engines (Cannon.js, Ammo.js)
  • Optimizing 3D game performance
  • Working with shaders and materials for game visuals
在以下场景激活此技能:
  • 使用Three.js构建3D网页游戏
  • 实现游戏机制(玩家移动、碰撞检测、计分系统)
  • 设置相机、光照与场景管理
  • 加载3D模型(GLTF、OBJ、FBX格式)
  • 处理用户输入(键盘、鼠标、触摸、游戏手柄)
  • 创建动画与角色控制器
  • 集成物理引擎(Cannon.js、Ammo.js)
  • 优化3D游戏性能
  • 使用着色器与材质优化游戏视觉效果

Quick Reference

快速参考

Basic Game Setup

基础游戏搭建

javascript
import * as THREE from 'three';

// Create scene, camera, renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Game loop
function animate(time) {
  requestAnimationFrame(animate);

  // Update game logic here
  updatePlayer(time);
  updateEnemies(time);
  checkCollisions();

  renderer.render(scene, camera);
}

animate();
javascript
import * as THREE from 'three';

// 创建场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 游戏循环
function animate(time) {
  requestAnimationFrame(animate);

  // 在此处更新游戏逻辑
  updatePlayer(time);
  updateEnemies(time);
  checkCollisions();

  renderer.render(scene, camera);
}

animate();

Player Controller (Third-Person)

第三人称玩家控制器

javascript
class PlayerController {
  constructor(camera, target) {
    this.camera = camera;
    this.target = target;
    this.distance = 10;
    this.height = 5;
    this.rotationSpeed = 0.005;
    this.moveSpeed = 0.1;
  }

  update(input) {
    // Movement
    const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.target.quaternion);
    const right = new THREE.Vector3(1, 0, 0).applyQuaternion(this.target.quaternion);

    if (input.forward) this.target.position.add(forward.multiplyScalar(this.moveSpeed));
    if (input.backward) this.target.position.add(forward.multiplyScalar(-this.moveSpeed));
    if (input.left) this.target.position.add(right.multiplyScalar(-this.moveSpeed));
    if (input.right) this.target.position.add(right.multiplyScalar(this.moveSpeed));

    // Rotation
    if (input.rotateLeft) this.target.rotation.y += this.rotationSpeed;
    if (input.rotateRight) this.target.rotation.y -= this.rotationSpeed;

    // Update camera position
    const offset = new THREE.Vector3(0, this.height, this.distance);
    offset.applyQuaternion(this.target.quaternion);
    this.camera.position.copy(this.target.position).add(offset);
    this.camera.lookAt(this.target.position);
  }
}
javascript
class PlayerController {
  constructor(camera, target) {
    this.camera = camera;
    this.target = target;
    this.distance = 10;
    this.height = 5;
    this.rotationSpeed = 0.005;
    this.moveSpeed = 0.1;
  }

  update(input) {
    // 移动逻辑
    const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.target.quaternion);
    const right = new THREE.Vector3(1, 0, 0).applyQuaternion(this.target.quaternion);

    if (input.forward) this.target.position.add(forward.multiplyScalar(this.moveSpeed));
    if (input.backward) this.target.position.add(forward.multiplyScalar(-this.moveSpeed));
    if (input.left) this.target.position.add(right.multiplyScalar(-this.moveSpeed));
    if (input.right) this.target.position.add(right.multiplyScalar(this.moveSpeed));

    // 旋转逻辑
    if (input.rotateLeft) this.target.rotation.y += this.rotationSpeed;
    if (input.rotateRight) this.target.rotation.y -= this.rotationSpeed;

    // 更新相机位置
    const offset = new THREE.Vector3(0, this.height, this.distance);
    offset.applyQuaternion(this.target.quaternion);
    this.camera.position.copy(this.target.position).add(offset);
    this.camera.lookAt(this.target.position);
  }
}

Input Handling

输入处理

javascript
class InputManager {
  constructor() {
    this.keys = {};
    this.mouse = { x: 0, y: 0, buttons: {} };

    window.addEventListener('keydown', (e) => this.keys[e.code] = true);
    window.addEventListener('keyup', (e) => this.keys[e.code] = false);
    window.addEventListener('mousemove', (e) => {
      this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
      this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
    });
  }

  getInput() {
    return {
      forward: this.keys['KeyW'] || this.keys['ArrowUp'],
      backward: this.keys['KeyS'] || this.keys['ArrowDown'],
      left: this.keys['KeyA'] || this.keys['ArrowLeft'],
      right: this.keys['KeyD'] || this.keys['ArrowRight'],
      jump: this.keys['Space'],
      action: this.keys['KeyE'],
      rotateLeft: this.keys['KeyQ'],
      rotateRight: this.keys['KeyE']
    };
  }
}
javascript
class InputManager {
  constructor() {
    this.keys = {};
    this.mouse = { x: 0, y: 0, buttons: {} };

    window.addEventListener('keydown', (e) => this.keys[e.code] = true);
    window.addEventListener('keyup', (e) => this.keys[e.code] = false);
    window.addEventListener('mousemove', (e) => {
      this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
      this.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
    });
  }

  getInput() {
    return {
      forward: this.keys['KeyW'] || this.keys['ArrowUp'],
      backward: this.keys['KeyS'] || this.keys['ArrowDown'],
      left: this.keys['KeyA'] || this.keys['ArrowLeft'],
      right: this.keys['KeyD'] || this.keys['ArrowRight'],
      jump: this.keys['Space'],
      action: this.keys['KeyE'],
      rotateLeft: this.keys['KeyQ'],
      rotateRight: this.keys['KeyE']
    };
  }
}

Collision Detection (Raycasting)

碰撞检测(射线投射)

javascript
function checkCollisions(player, obstacles) {
  const raycaster = new THREE.Raycaster();
  const directions = [
    new THREE.Vector3(1, 0, 0),   // right
    new THREE.Vector3(-1, 0, 0),  // left
    new THREE.Vector3(0, 0, 1),   // forward
    new THREE.Vector3(0, 0, -1),  // backward
  ];

  for (const direction of directions) {
    raycaster.set(player.position, direction);
    const intersects = raycaster.intersectObjects(obstacles);

    if (intersects.length > 0 && intersects[0].distance < 1.0) {
      return {
        collision: true,
        object: intersects[0].object,
        distance: intersects[0].distance,
        point: intersects[0].point
      };
    }
  }

  return { collision: false };
}
javascript
function checkCollisions(player, obstacles) {
  const raycaster = new THREE.Raycaster();
  const directions = [
    new THREE.Vector3(1, 0, 0),   // 右
    new THREE.Vector3(-1, 0, 0),  // 左
    new THREE.Vector3(0, 0, 1),   // 前
    new THREE.Vector3(0, 0, -1),  // 后
  ];

  for (const direction of directions) {
    raycaster.set(player.position, direction);
    const intersects = raycaster.intersectObjects(obstacles);

    if (intersects.length > 0 && intersects[0].distance < 1.0) {
      return {
        collision: true,
        object: intersects[0].object,
        distance: intersects[0].distance,
        point: intersects[0].point
      };
    }
  }

  return { collision: false };
}

Loading 3D Models (GLTF)

加载3D模型(GLTF格式)

javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

function loadCharacter(path) {
  return new Promise((resolve, reject) => {
    loader.load(
      path,
      (gltf) => {
        const model = gltf.scene;
        model.scale.set(1, 1, 1);
        scene.add(model);

        // Setup animations if available
        const mixer = new THREE.AnimationMixer(model);
        const animations = {};
        gltf.animations.forEach(clip => {
          animations[clip.name] = mixer.clipAction(clip);
        });

        resolve({ model, mixer, animations });
      },
      (progress) => {
        console.log(`Loading: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
      },
      (error) => reject(error)
    );
  });
}

// Usage
const character = await loadCharacter('/models/character.glb');
character.animations.idle.play();
javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

function loadCharacter(path) {
  return new Promise((resolve, reject) => {
    loader.load(
      path,
      (gltf) => {
        const model = gltf.scene;
        model.scale.set(1, 1, 1);
        scene.add(model);

        // 如果有动画则设置动画
        const mixer = new THREE.AnimationMixer(model);
        const animations = {};
        gltf.animations.forEach(clip => {
          animations[clip.name] = mixer.clipAction(clip);
        });

        resolve({ model, mixer, animations });
      },
      (progress) => {
        console.log(`加载进度: ${(progress.loaded / progress.total * 100).toFixed(2)}%`);
      },
      (error) => reject(error)
    );
  });
}

// 使用示例
const character = await loadCharacter('/models/character.glb');
character.animations.idle.play();

Basic Physics (Gravity & Jumping)

基础物理系统(重力与跳跃)

javascript
class PhysicsBody {
  constructor(mesh) {
    this.mesh = mesh;
    this.velocity = new THREE.Vector3();
    this.onGround = false;
    this.gravity = -9.8;
    this.jumpPower = 5;
  }

  update(deltaTime) {
    // Apply gravity
    if (!this.onGround) {
      this.velocity.y += this.gravity * deltaTime;
    }

    // Apply velocity
    this.mesh.position.add(this.velocity.clone().multiplyScalar(deltaTime));

    // Ground check
    if (this.mesh.position.y <= 0) {
      this.mesh.position.y = 0;
      this.velocity.y = 0;
      this.onGround = true;
    }
  }

  jump() {
    if (this.onGround) {
      this.velocity.y = this.jumpPower;
      this.onGround = false;
    }
  }
}
javascript
class PhysicsBody {
  constructor(mesh) {
    this.mesh = mesh;
    this.velocity = new THREE.Vector3();
    this.onGround = false;
    this.gravity = -9.8;
    this.jumpPower = 5;
  }

  update(deltaTime) {
    // 应用重力
    if (!this.onGround) {
      this.velocity.y += this.gravity * deltaTime;
    }

    // 应用速度
    this.mesh.position.add(this.velocity.clone().multiplyScalar(deltaTime));

    // 地面检测
    if (this.mesh.position.y <= 0) {
      this.mesh.position.y = 0;
      this.velocity.y = 0;
      this.onGround = true;
    }
  }

  jump() {
    if (this.onGround) {
      this.velocity.y = this.jumpPower;
      this.onGround = false;
    }
  }
}

Interactive Objects (Picking)

交互式对象(拾取)

javascript
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

function onMouseClick(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(interactableObjects);

  if (intersects.length > 0) {
    const object = intersects[0].object;
    object.userData.onInteract?.();
  }
}

window.addEventListener('click', onMouseClick);
javascript
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

function onMouseClick(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(interactableObjects);

  if (intersects.length > 0) {
    const object = intersects[0].object;
    object.userData.onInteract?.();
  }
}

window.addEventListener('click', onMouseClick);

Health & Damage System

生命值与伤害系统

javascript
class Entity {
  constructor(mesh, maxHealth) {
    this.mesh = mesh;
    this.maxHealth = maxHealth;
    this.health = maxHealth;
    this.isDead = false;
  }

  takeDamage(amount) {
    if (this.isDead) return;

    this.health = Math.max(0, this.health - amount);

    if (this.health === 0) {
      this.die();
    }

    return this.health;
  }

  heal(amount) {
    this.health = Math.min(this.maxHealth, this.health + amount);
    return this.health;
  }

  die() {
    this.isDead = true;
    this.mesh.visible = false;
    // Trigger death animation, effects, etc.
  }
}
javascript
class Entity {
  constructor(mesh, maxHealth) {
    this.mesh = mesh;
    this.maxHealth = maxHealth;
    this.health = maxHealth;
    this.isDead = false;
  }

  takeDamage(amount) {
    if (this.isDead) return;

    this.health = Math.max(0, this.health - amount);

    if (this.health === 0) {
      this.die();
    }

    return this.health;
  }

  heal(amount) {
    this.health = Math.min(this.maxHealth, this.health + amount);
    return this.health;
  }

  die() {
    this.isDead = true;
    this.mesh.visible = false;
    // 触发死亡动画、特效等
  }
}

Key Concepts

核心概念

Scene Graph

场景图

  • Organize game objects hierarchically
  • Use groups for complex objects
  • Parent-child transformations
  • 按层级组织游戏对象
  • 使用组管理复杂对象
  • 父子对象变换关系

Game Loop

游戏循环

  • Use
    requestAnimationFrame
    for 60fps
  • Calculate delta time for frame-independent movement
  • Separate update logic from rendering
  • 使用
    requestAnimationFrame
    实现60fps帧率
  • 计算增量时间实现帧率无关的移动
  • 将更新逻辑与渲染逻辑分离

Camera Systems

相机系统

  • PerspectiveCamera: First/third-person games
  • OrthographicCamera: 2D/isometric games
  • Implement camera follow and smooth transitions
  • PerspectiveCamera:第一/第三人称游戏
  • OrthographicCamera:2D/等距视角游戏
  • 实现相机跟随与平滑过渡

Lighting

光照

  • AmbientLight: Base illumination
  • DirectionalLight: Sun/moonlight with shadows
  • PointLight: Torches, explosions
  • SpotLight: Flashlights, stage lights
  • AmbientLight:基础环境光
  • DirectionalLight:模拟日月光,支持阴影
  • PointLight:火把、爆炸等点光源
  • SpotLight:手电筒、舞台灯光等聚光灯

Performance Optimization

性能优化

  • Use instancing for repeated objects
  • Implement frustum culling
  • Use LOD (Level of Detail) for distant objects
  • Minimize draw calls
  • Use texture atlases
  • Enable shadow map optimization
  • 对重复对象使用实例化渲染
  • 实现视锥体剔除
  • 对远距离对象使用LOD(细节层次)技术
  • 最小化绘制调用
  • 使用纹理图集
  • 优化阴影贴图

Asset Loading

资源加载

  • Preload all assets before game start
  • Show loading progress bar
  • Use LoadingManager for coordination
  • Cache loaded assets
  • 游戏启动前预加载所有资源
  • 显示加载进度条
  • 使用LoadingManager协调加载过程
  • 缓存已加载资源

Common Game Patterns

常见游戏模式

State Machine (Game States)

状态机(游戏状态)

javascript
class GameStateMachine {
  constructor() {
    this.states = {
      menu: new MenuState(),
      playing: new PlayingState(),
      paused: new PausedState(),
      gameOver: new GameOverState()
    };
    this.currentState = this.states.menu;
  }

  changeState(stateName) {
    this.currentState.exit();
    this.currentState = this.states[stateName];
    this.currentState.enter();
  }

  update(deltaTime) {
    this.currentState.update(deltaTime);
  }
}
javascript
class GameStateMachine {
  constructor() {
    this.states = {
      menu: new MenuState(),
      playing: new PlayingState(),
      paused: new PausedState(),
      gameOver: new GameOverState()
    };
    this.currentState = this.states.menu;
  }

  changeState(stateName) {
    this.currentState.exit();
    this.currentState = this.states[stateName];
    this.currentState.enter();
  }

  update(deltaTime) {
    this.currentState.update(deltaTime);
  }
}

Object Pooling

对象池

javascript
class ObjectPool {
  constructor(factory, initialSize = 10) {
    this.factory = factory;
    this.available = [];
    this.inUse = [];

    for (let i = 0; i < initialSize; i++) {
      this.available.push(factory());
    }
  }

  acquire() {
    let obj = this.available.pop();
    if (!obj) obj = this.factory();
    this.inUse.push(obj);
    return obj;
  }

  release(obj) {
    const index = this.inUse.indexOf(obj);
    if (index > -1) {
      this.inUse.splice(index, 1);
      this.available.push(obj);
    }
  }
}

// Usage
const bulletPool = new ObjectPool(() => createBullet(), 20);
const bullet = bulletPool.acquire();
// ... use bullet
bulletPool.release(bullet);
javascript
class ObjectPool {
  constructor(factory, initialSize = 10) {
    this.factory = factory;
    this.available = [];
    this.inUse = [];

    for (let i = 0; i < initialSize; i++) {
      this.available.push(factory());
    }
  }

  acquire() {
    let obj = this.available.pop();
    if (!obj) obj = this.factory();
    this.inUse.push(obj);
    return obj;
  }

  release(obj) {
    const index = this.inUse.indexOf(obj);
    if (index > -1) {
      this.inUse.splice(index, 1);
      this.available.push(obj);
    }
  }
}

// 使用示例
const bulletPool = new ObjectPool(() => createBullet(), 20);
const bullet = bulletPool.acquire();
// ... 使用子弹
bulletPool.release(bullet);

Reference Files

参考文档

Detailed documentation organized by topic:
  • getting_started.md - Three.js fundamentals, setup, and basic concepts
  • game_development.md - Game loop, player controllers, game mechanics
  • scene_graph.md - Scene organization, hierarchy, transformations
  • materials.md - Material types, shaders, visual effects
  • textures.md - Texture loading, UV mapping, atlases
  • lighting.md - Light types, shadows, HDR
  • cameras.md - Camera types, controls, viewport management
  • geometry.md - Built-in geometries, custom geometry, buffers
  • loading.md - Asset loading (models, textures, audio)
  • animation.md - Animation system, skeletal animation, tweens
  • interactivity.md - Raycasting, picking, UI integration
  • effects.md - Post-processing, particles, fog
按主题分类的详细文档:
  • getting_started.md - Three.js基础、搭建与核心概念
  • game_development.md - 游戏循环、玩家控制器、游戏机制
  • scene_graph.md - 场景组织、层级结构、变换系统
  • materials.md - 材质类型、着色器、视觉效果
  • textures.md - 纹理加载、UV映射、纹理图集
  • lighting.md - 光源类型、阴影、HDR
  • cameras.md - 相机类型、控制器、视口管理
  • geometry.md - 内置几何体、自定义几何体、缓冲几何体
  • loading.md - 资源加载(模型、纹理、音频)
  • animation.md - 动画系统、骨骼动画、补间动画
  • interactivity.md - 射线投射、对象拾取、UI集成
  • effects.md - 后处理、粒子系统、雾效

Resources

资源链接

Official Documentation

官方文档

Physics Integration

物理引擎集成

  • Cannon.js: Lightweight 3D physics
  • Ammo.js: Full Bullet physics engine port
  • Rapier: High-performance physics
  • Cannon.js:轻量级3D物理引擎
  • Ammo.js:完整Bullet物理引擎移植版
  • Rapier:高性能物理引擎

Useful Libraries

实用库

  • three-mesh-bvh: Fast raycasting
  • three-pathfinding: Navigation meshes
  • postprocessing: Advanced effects
  • three-mesh-bvh:快速射线投射
  • three-pathfinding:导航网格
  • postprocessing:高级后处理效果

Working with This Skill

使用此技能的建议

For Beginners

面向初学者

  1. Start with basic scene setup
  2. Learn the coordinate system
  3. Understand the game loop
  4. Practice with simple shapes before models
  1. 从基础场景搭建开始
  2. 理解Three.js坐标系
  3. 掌握游戏循环逻辑
  4. 先练习简单几何体,再使用3D模型

For Game Development

面向游戏开发者

  1. Plan your game architecture
  2. Implement input handling first
  3. Build a simple player controller
  4. Add gameplay mechanics incrementally
  5. Optimize performance throughout
  1. 规划游戏架构
  2. 优先实现输入处理
  3. 构建基础玩家控制器
  4. 逐步添加游戏机制
  5. 全程关注性能优化

For Advanced Features

面向高级功能开发

  1. Integrate physics engines
  2. Implement advanced shaders
  3. Add post-processing effects
  4. Build multiplayer networking
  1. 集成物理引擎
  2. 实现高级着色器
  3. 添加后处理效果
  4. 构建多人网络功能

Notes

注意事项

  • Three.js uses a right-handed coordinate system (X right, Y up, Z out)
  • Optimize early: profile regularly, minimize draw calls
  • Use development builds for debugging, production builds for release
  • Consider WebGL 2 features for modern browsers
  • Mobile performance requires careful optimization
  • Three.js使用右手坐标系(X轴向右,Y轴向上,Z轴向外)
  • 尽早优化:定期分析性能,最小化绘制调用
  • 开发阶段使用开发版本调试,生产环境使用生产版本
  • 针对现代浏览器可使用WebGL 2特性
  • 移动端性能需要重点优化