WebXR教学 05 项目3 太空飞船小游戏

准备工作

自动创建 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 

说明:

  1. 自动创建 package.json 文件
  2. -y 参数表示接受所有默认选项
  3. 生成包含项目基本信息、依赖和脚本的基础配置文件
    npm install three vite 说明:
  4. three - 安装 Three.js 3D 图形库(当前项目核心依赖)
  5. vite - 安装现代前端构建工具(用于开发/打包)
  6. 安装后会生成 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();
相关推荐
刘梦凡呀5 分钟前
C# .NET Core 批量下载文件
windows·c#·.netcore
Lilith的AI学习日记21 分钟前
n8n 中文系列教程_05.如何在本机部署/安装 n8n(详细图文教程)
运维·windows·macos·ai编程·n8n
广龙宇1 小时前
【一起学Rust】使用Thunk工具链实现Rust应用对Windows XP/7的兼容性适配实战
开发语言·windows·rust
扛枪的书生1 小时前
Windows 提权指南
windows·渗透·kali·提权
qq_431331352 小时前
Unity ML-Agents + VScode 环境搭建 Windows
windows·vscode·unity·强化学习
h39742 小时前
MFC文件-屏幕录像
c++·windows·音视频·mfc
RQ_ghylls4 小时前
21.disql命令登录达梦数据库,查询并操作数据库
java·linux·开发语言·数据库·windows·docker·数据分析
topfine4 小时前
Win10 C盘空间不足清理方法
windows
YuSun_WK9 小时前
.whl文件
windows