threejs-game
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseThree.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 for 60fps
requestAnimationFrame - Calculate delta time for frame-independent movement
- Separate update logic from rendering
- 使用实现60fps帧率
requestAnimationFrame - 计算增量时间实现帧率无关的移动
- 将更新逻辑与渲染逻辑分离
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
官方文档
- Three.js Manual: https://threejs.org/manual/
- Three.js API: https://threejs.org/docs/
- Three.js Examples: https://threejs.org/examples/
- Three.js手册:https://threejs.org/manual/
- Three.js API文档:https://threejs.org/docs/
- Three.js示例:https://threejs.org/examples/
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
面向初学者
- Start with basic scene setup
- Learn the coordinate system
- Understand the game loop
- Practice with simple shapes before models
- 从基础场景搭建开始
- 理解Three.js坐标系
- 掌握游戏循环逻辑
- 先练习简单几何体,再使用3D模型
For Game Development
面向游戏开发者
- Plan your game architecture
- Implement input handling first
- Build a simple player controller
- Add gameplay mechanics incrementally
- Optimize performance throughout
- 规划游戏架构
- 优先实现输入处理
- 构建基础玩家控制器
- 逐步添加游戏机制
- 全程关注性能优化
For Advanced Features
面向高级功能开发
- Integrate physics engines
- Implement advanced shaders
- Add post-processing effects
- Build multiplayer networking
- 集成物理引擎
- 实现高级着色器
- 添加后处理效果
- 构建多人网络功能
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特性
- 移动端性能需要重点优化