准备工作
自动创建 package.json 文件
bash
npm init -y
安装Three.js 3D 图形库,安装现代前端构建工具Vite(用于开发/打包)
bash
npm install three vite
启动 Vite 开发服务器(推荐)(正式项目开发)
bash
npm run dev
启动 Vite 开发服务器(快速测试或临时使用)
bash
npx vite
npm init -y
说明:
- 自动创建 package.json 文件
- -y 参数表示接受所有默认选项
- 生成包含项目基本信息、依赖和脚本的基础配置文件
npm install three vite 说明: - three - 安装 Three.js 3D 图形库(当前项目核心依赖)
- vite - 安装现代前端构建工具(用于开发/打包)
- 安装后会生成 node_modules 目录和 package-lock.json
VS Code颜色高亮插件:Color Highlight
项目结构

代码
package.json
json
{
"name": "test",
"version": "1.0.0",
"main": "main.js",
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"three": "^0.148.0",
"vite": "^6.2.0"
}
}
index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>太空飞船小游戏</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="score">0</div>
<div id="gameOver">游戏结束</div>
<script type="module" src="./main.js"></script>
</body>
</html>
style.css
body {
margin: 0;
/* background-color: black; */
overflow: hidden;
}
#gameOver {
position: absolute;
/* 以自身宽度和高度向左、上移动一定距离,使其居中 */
transform: translate(-50%, -50%);
left: 50%;
top: 50%;
color: red;
display: none;
font-size: 48px;
}
#score {
position: absolute;
transform: translate(-50%,0);
left: 50%;
color: white;
display: block;
font-size: 50px;
margin: 0 auto;
}
main.js
javascript
// ============== 全局声明区 ==============
import * as THREE from 'three';
// 游戏状态相关变量
let scene, camera, renderer, ship, stone;
let stones = [];
let moveLeft = false, moveRight = false;
let gameActive = true;
let score = 0;
let lastScoreUpdate = Date.now();
// ============== 核心逻辑模块 ==============
// 初始化游戏基础设置
function init(){
// 场景初始化三要素
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
// 渲染基础配置
scene.background = new THREE.Color(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.z = 10;
// 光照系统初始化
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
// 游戏实体初始化
ship = new Ship(scene);
stone = new Stone(scene);
// 事件系统启动
setupEventListeners();
// 启动游戏主循环
gameLoop();
}
// 主游戏循环(每帧执行)
function gameLoop(){
if(!gameActive) return;
requestAnimationFrame(gameLoop);
// === 分数系统 ===
const now = Date.now();
if (now - lastScoreUpdate >= 1000) {
score++;
document.getElementById('score').textContent = score;
lastScoreUpdate = now;
}
// === 玩家控制 ===
if(moveLeft) ship.move('left');
if(moveRight) ship.move('right');
// === 陨石管理系统 ===
// 生成逻辑(30%概率/帧)
if(Math.random() < 0.3) {
stones.push(new Stone(scene));
}
// 更新循环
stones.forEach((stone, index) => {
// 运动逻辑
stone.move();
// 碰撞检测
if(checkCollision(ship.object, stone.object)) {
endGame();
}
// 对象回收
if(stone.isOutOfScreen()) {
scene.remove(stone.object);
stones.splice(index, 1);
}
});
// 场景渲染
renderer.render(scene, camera);
}
// ============== 输入控制模块 ==============
function setupEventListeners() {
// 键盘事件监听
document.addEventListener('keydown', (e) => {
if(e.key === 'ArrowLeft') moveLeft = true;
if(e.key === 'ArrowRight') moveRight = true;
});
document.addEventListener('keyup', (e) => {
if(e.key === 'ArrowLeft') moveLeft = false;
if(e.key === 'ArrowRight') moveRight = false;
});
// 窗口自适应
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
}
// ============== 游戏逻辑模块 ==============
// 简易距离碰撞检测
function checkCollision(objA, objB) {
return objA.position.distanceTo(objB.position) < 1.2;
}
// 游戏结束处理
function endGame() {
gameActive = false;
document.getElementById('gameOver').style.display = 'block';
}
// ============== 游戏对象类 ==============
// 玩家飞船实体
class Ship {
constructor(scene) {
this.object = this.createShip();
this.speed = 0.2;
scene.add(this.object);
}
// 飞船建模
createShip() {
const geometry = new THREE.ConeGeometry(0.5, 1, 8);
const material = new THREE.MeshBasicMaterial({color: 0x00ff00});
const ship = new THREE.Mesh(geometry, material);
geometry.rotateX(Math.PI/2);
ship.position.set(0, -4, 0);
// 线框增强显示
const wireframe = new THREE.LineSegments(
new THREE.EdgesGeometry(geometry),
new THREE.LineBasicMaterial({ color: 0xffffff })
);
ship.add(wireframe);
return ship;
}
// 移动控制逻辑
move(direction) {
const maxX = 10;
if(direction === 'left' && this.object.position.x > -maxX) {
this.object.position.x -= this.speed;
}
if(direction === 'right' && this.object.position.x < maxX) {
this.object.position.x += this.speed;
}
}
}
// 陨石实体
class Stone {
constructor(scene) {
this.object = this.create();
this.speed = 0.1;
scene.add(this.object);
this.resetPosition();
}
// 陨石建模
create() {
return new THREE.Mesh(
new THREE.IcosahedronGeometry(0.5, 1),
new THREE.MeshPhongMaterial({
color: 0xff4500,
emissive: 0xff6347,
emissiveIntensity: 0.6,
specular: 0xffffff,
shininess: 50,
wireframe: true
})
);
}
// 位置初始化
resetPosition() {
this.object.position.set(
(Math.random() - 0.5) * 20,
9,
0
);
}
// 下落逻辑
move() {
this.object.position.y -= this.speed;
}
// 边界检测
isOutOfScreen() {
return this.object.position.y < -5;
}
}
// ============== 程序入口 ==============
init();