当前位置: 首页 > news >正文

第29节:第二阶段总结 - 打造一个3D游戏原型

第29节:第二阶段总结 - 打造一个3D游戏原型

在这里插入图片描述

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,可以分享一下给大家。点击跳转到网站。
https://www.captainbed.cn/ccc

在这里插入图片描述

经过前面28节的深入学习,我们已经掌握了Three.js的核心技术和高级特性。本节将综合运用所学知识,构建一个完整的3D游戏原型 - “星际探索者”。这是一个融合了物理仿真、网络同步、视觉效果和交互体验的综合性项目。

游戏架构总览:

星际探索者游戏
核心引擎
游戏逻辑
网络系统
渲染系统
场景管理
物理引擎
资源加载
玩家控制
AI系统
任务系统
多人同步
实时通信
状态管理
视觉效果
后期处理
性能优化

游戏设计文档

核心玩法

  • 玩家角色: 太空飞船驾驶员
  • 主要目标: 探索星系、收集资源、完成任务
  • 游戏机制: 飞行控制、战斗系统、资源管理
  • 多人模式: 合作探索、竞技对战

技术特性

模块技术实现性能目标
场景渲染多层级LOD + 实例化渲染60 FPS稳定
物理仿真Cannon-es + 自定义碰撞实时物理计算
网络同步WebSocket + 状态预测< 100ms延迟
视觉效果PBR材质 + 后期处理电影级画质

完整游戏实现

<template><div class="game-container"><!-- 主游戏画布 --><canvas ref="gameCanvas" class="game-canvas"></canvas><!-- HUD界面 --><div class="hud-overlay"><!-- 顶部状态栏 --><div class="top-bar"><div class="player-info"><span class="player-name">玩家 {{ playerId }}</span><div class="health-bar"><div class="health-fill" :style="healthStyle"></div><span class="health-text">{{ playerHealth }} / 100</span></div></div><div class="mission-info"><h3>当前任务: {{ currentMission }}</h3><div class="mission-progress"><div class="progress-fill" :style="missionProgressStyle"></div></div></div><div class="resource-display"><div class="resource-item"><span class="resource-icon">⛽</span><span class="resource-value">{{ resources.fuel }}</span></div><div class="resource-item"><span class="resource-icon">💎</span><span class="resource-value">{{ resources.minerals }}</span></div><div class="resource-item"><span class="resource-icon">🔧</span><span class="resource-value">{{ resources.parts }}</span></div></div></div><!-- 雷达显示 --><div class="radar-container"><div class="radar-display"><canvas ref="radarCanvas" class="radar-canvas"></canvas></div><div class="radar-info"><span>附近物体: {{ nearbyObjects }}</span><span>威胁等级: {{ threatLevel }}</span></div></div><!-- 控制提示 --><div class="control-hints"><div class="hint-group"><kbd>WASD</kbd><span>移动飞船</span></div><div class="hint-group"><kbd>鼠标</kbd><span>控制视角</span></div><div class="hint-group"><kbd>空格</kbd><span>发射武器</span></div><div class="hint-group"><kbd>E</kbd><span>互动/收集</span></div></div></div><!-- 游戏菜单 --><div v-if="showMenu" class="game-menu"><div class="menu-content"><h1>星际探索者</h1><div class="menu-section"><h2>游戏状态</h2><div class="menu-stats"><div class="stat-item"><span>游戏时间:</span><span>{{ formatGameTime(gameTime) }}</span></div><div class="stat-item"><span>探索进度:</span><span>{{ explorationProgress }}%</span></div><div class="stat-item"><span>击败敌人:</span><span>{{ enemiesDefeated }}</span></div></div></div><div class="menu-section"><h2>多人游戏</h2><div class="multiplayer-controls"><button @click="toggleMultiplayer" class="menu-button":class="{ active: isMultiplayer }">{{ isMultiplayer ? '离开多人游戏' : '加入多人游戏' }}</button><div v-if="isMultiplayer" class="players-online"><span>在线玩家: {{ onlinePlayers }}</span></div></div></div><div class="menu-section"><h2>设置</h2><div class="settings-controls"><label class="setting-item"><span>图形质量:</span><select v-model="graphicsQuality"><option value="low">低</option><option value="medium">中</option><option value="high">高</option><option value="ultra">超高</option></select></label><label class="setting-item"><span>声音音量:</span><input type="range" v-model="soundVolume" min="0" max="100"></label><label class="setting-item"><input type="checkbox" v-model="enablePostProcessing">启用后期处理</label></div></div><div class="menu-actions"><button @click="resumeGame" class="menu-button primary">继续游戏</button><button @click="restartGame" class="menu-button">重新开始</button><button @click="exitGame" class="menu-button danger">退出游戏</button></div></div></div><!-- 加载界面 --><div v-if="isLoading" class="loading-screen"><div class="loading-content"><div class="loading-animation"><div class="spaceship-loader"></div><div class="loading-particles"></div></div><h2>初始化星际引擎...</h2><div class="loading-progress"><div class="progress-bar"><div class="progress-fill" :style="loadingProgressStyle"></div></div><span class="progress-text">{{ loadingMessage }}</span></div></div></div></div>
</template><script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
import Cannon from 'cannon-es';// 游戏核心引擎
class StarExplorerEngine {constructor(canvas) {this.canvas = canvas;this.scene = null;this.camera = null;this.renderer = null;this.composer = null;this.controls = null;this.world = null;this.gameObjects = new Map();this.players = new Map();this.projectiles = new Set();this.resources = new Set();this.clock = new THREE.Clock();this.isRunning = false;this.init();}async init() {await this.initGraphics();await this.initPhysics();await this.initGameWorld();this.initEventHandlers();}// 初始化图形系统async initGraphics() {// 创建场景this.scene = new THREE.Scene();this.scene.background = new THREE.Color(0x000010);this.scene.fog = new THREE.Fog(0x000010, 10, 1000);// 创建相机this.camera = new THREE.PerspectiveCamera(75,this.canvas.clientWidth / this.canvas.clientHeight,0.1,10000);this.camera.position.set(0, 50, 100);// 创建渲染器this.renderer = new THREE.WebGLRenderer({canvas: this.canvas,antialias: true,powerPreference: "high-performance"});this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));this.renderer.shadowMap.enabled = true;this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;this.renderer.toneMapping = THREE.ACESFilmicToneMapping;this.renderer.toneMappingExposure = 1.2;// 初始化后期处理this.initPostProcessing();// 添加控制器this.controls = new OrbitControls(this.camera, this.renderer.domElement);this.controls.enableDamping = true;this.controls.dampingFactor = 0.05;this.controls.minDistance = 10;this.controls.maxDistance = 500;}// 初始化后期处理initPostProcessing() {this.composer = new EffectComposer(this.renderer);const renderPass = new RenderPass(this.scene, this.camera);this.composer.addPass(renderPass);const bloomPass = new UnrealBloomPass(new THREE.Vector2(this.canvas.clientWidth, this.canvas.clientHeight),1.5, 0.4, 0.85);this.composer.addPass(bloomPass);const outputPass = new OutputPass();this.composer.addPass(outputPass);}// 初始化物理世界async initPhysics() {this.world = new Cannon.World();this.world.gravity.set(0, 0, 0); // 太空无重力this.world.broadphase = new Cannon.NaiveBroadphase();this.world.solver.iterations = 10;// 创建物理材质this.materials = {default: new Cannon.Material('default'),player: new Cannon.Material('player'),projectile: new Cannon.Material('projectile')};// 设置材质接触参数this.setupMaterialContacts();}// 设置材质接触setupMaterialContacts() {const defaultContact = new Cannon.ContactMaterial(this.materials.default,this.materials.default,{ friction: 0.3, restitution: 0.7 });const playerProjectileContact = new Cannon.ContactMaterial(this.materials.player,this.materials.projectile,{ friction: 0.0, restitution: 0.9 });this.world.addContactMaterial(defaultContact);this.world.addContactMaterial(playerProjectileContact);}// 初始化游戏世界async initGameWorld() {await this.createStarfield();await this.createPlanets();await this.createSpaceStations();this.createAsteroidField();this.setupLighting();}// 创建星空背景async createStarfield() {const starGeometry = new THREE.BufferGeometry();const starCount = 10000;const positions = new Float32Array(starCount * 3);const colors = new Float32Array(starCount * 3);const sizes = new Float32Array(starCount);for (let i = 0; i < starCount; i++) {const i3 = i * 3;// 随机位置positions[i3] = (Math.random() - 0.5) * 2000;positions[i3 + 1] = (Math.random() - 0.5) * 2000;positions[i3 + 2] = (Math.random() - 0.5) * 2000;// 随机颜色const color = new THREE.Color();color.setHSL(Math.random() * 0.2 + 0.5, 0.8, Math.random() * 0.5 + 0.5);colors[i3] = color.r;colors[i3 + 1] = color.g;colors[i3 + 2] = color.b;// 随机大小sizes[i] = Math.random() * 2 + 0.5;}starGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));starGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));starGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));const starMaterial = new THREE.PointsMaterial({size: 2,sizeAttenuation: true,vertexColors: true,transparent: true,opacity: 0.8});const starField = new THREE.Points(starGeometry, starMaterial);this.scene.add(starField);}// 创建行星async createPlanets() {const planets = [{ position: [200, 0, 0], size: 20, color: 0xff4444, name: '火星' },{ position: [-300, 50, 100], size: 30, color: 0x44ff44, name: '绿洲星' },{ position: [0, -150, -200], size: 25, color: 0x4444ff, name: '海洋星' }];for (const planetData of planets) {const planet = await this.createPlanet(planetData);this.gameObjects.set(planetData.name, planet);}}// 创建单个行星async createPlanet(data) {const geometry = new THREE.SphereGeometry(data.size, 32, 32);const material = new THREE.MeshStandardMaterial({color: data.color,roughness: 0.8,metalness: 0.2,emissive: data.color,emissiveIntensity: 0.1});const planet = new THREE.Mesh(geometry, material);planet.position.set(...data.position);planet.castShadow = true;planet.receiveShadow = true;// 添加行星标签const label = this.createPlanetLabel(data.name);planet.add(label);// 创建物理体const shape = new Cannon.Sphere(data.size);const body = new Cannon.Body({mass: 0, // 静态物体material: this.materials.default,shape: shape});body.position.set(...data.position);this.world.addBody(body);planet.userData.physicsBody = body;this.scene.add(planet);return planet;}// 创建行星标签createPlanetLabel(name) {const canvas = document.createElement('canvas');const context = canvas.getContext('2d');canvas.width = 256;canvas.height = 64;context.fillStyle = 'rgba(0, 0, 0, 0.7)';context.fillRect(0, 0, canvas.width, canvas.height);context.font = 'bold 24px Arial';context.fillStyle = 'white';context.textAlign = 'center';context.fillText(name, canvas.width / 2, canvas.height / 2 + 8);const texture = new THREE.CanvasTexture(canvas);const material = new THREE.SpriteMaterial({ map: texture });const sprite = new THREE.Sprite(material);sprite.scale.set(20, 5, 1);sprite.position.y = 30;return sprite;}// 创建空间站async createSpaceStations() {const stationGeometry = new THREE.CylinderGeometry(5, 8, 15, 8);const stationMaterial = new THREE.MeshStandardMaterial({color: 0x888888,roughness: 0.7,metalness: 0.8,emissive: 0x444444});const station = new THREE.Mesh(stationGeometry, stationMaterial);station.position.set(0, 0, 150);station.rotation.x = Math.PI / 2;station.castShadow = true;// 添加灯光效果const stationLight = new THREE.PointLight(0x00ffff, 1, 50);station.add(stationLight);this.scene.add(station);this.gameObjects.set('mainStation', station);}// 创建小行星带createAsteroidField() {const asteroidCount = 200;for (let i = 0; i < asteroidCount; i++) {const asteroid = this.createAsteroid();this.gameObjects.set(`asteroid_${i}`, asteroid);}}// 创建小行星createAsteroid() {const size = Math.random() * 3 + 1;const geometry = new THREE.DodecahedronGeometry(size, 0);const material = new THREE.MeshStandardMaterial({color: 0x8B4513,roughness: 0.9,metalness: 0.1});const asteroid = new THREE.Mesh(geometry, material);// 随机位置const angle = Math.random() * Math.PI * 2;const distance = Math.random() * 100 + 50;asteroid.position.set(Math.cos(angle) * distance,(Math.random() - 0.5) * 50,Math.sin(angle) * distance);// 随机旋转asteroid.rotation.set(Math.random() * Math.PI,Math.random() * Math.PI,Math.random() * Math.PI);asteroid.castShadow = true;// 物理体const shape = new Cannon.Sphere(size);const body = new Cannon.Body({mass: 1,material: this.materials.default,shape: shape});body.position.copy(asteroid.position);// 随机角速度body.angularVelocity.set((Math.random() - 0.5) * 0.1,(Math.random() - 0.5) * 0.1,(Math.random() - 0.5) * 0.1);this.world.addBody(body);asteroid.userData.physicsBody = body;this.scene.add(asteroid);return asteroid;}// 设置光照setupLighting() {// 环境光const ambientLight = new THREE.AmbientLight(0x404040, 0.3);this.scene.add(ambientLight);// 方向光(模拟太阳)const sunLight = new THREE.DirectionalLight(0xffffff, 1);sunLight.position.set(100, 100, 50);sunLight.castShadow = true;sunLight.shadow.mapSize.set(2048, 2048);sunLight.shadow.camera.near = 0.5;sunLight.shadow.camera.far = 500;sunLight.shadow.camera.left = -100;sunLight.shadow.camera.right = 100;sunLight.shadow.camera.top = 100;sunLight.shadow.camera.bottom = -100;this.scene.add(sunLight);// 点光源(空间站等)const pointLight = new THREE.PointLight(0x00aaff, 0.5, 100);pointLight.position.set(0, 0, 150);this.scene.add(pointLight);}// 初始化事件处理器initEventHandlers() {window.addEventListener('resize', this.handleResize.bind(this));// 键盘控制this.keys = {};document.addEventListener('keydown', (event) => {this.keys[event.code] = true;});document.addEventListener('keyup', (event) => {this.keys[event.code] = false;});}// 处理窗口大小变化handleResize() {if (!this.camera || !this.renderer) return;this.camera.aspect = this.canvas.clientWidth / this.canvas.clientHeight;this.camera.updateProjectionMatrix();this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);this.composer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);}// 创建玩家飞船createPlayerShip(playerId, position = [0, 0, 0]) {const shipGroup = new THREE.Group();// 飞船主体const bodyGeometry = new THREE.ConeGeometry(2, 6, 8);const bodyMaterial = new THREE.MeshStandardMaterial({color: 0x00aaff,roughness: 0.3,metalness: 0.8,emissive: 0x0044aa});const body = new THREE.Mesh(bodyGeometry, bodyMaterial);body.rotation.x = Math.PI;body.castShadow = true;shipGroup.add(body);// 机翼const wingGeometry = new THREE.BoxGeometry(6, 0.5, 2);const wingMaterial = new THREE.MeshStandardMaterial({color: 0x0088ff,roughness: 0.5,metalness: 0.6});const leftWing = new THREE.Mesh(wingGeometry, wingMaterial);const rightWing = new THREE.Mesh(wingGeometry, wingMaterial);leftWing.position.set(-3, 0, 0);rightWing.position.set(3, 0, 0);shipGroup.add(leftWing);shipGroup.add(rightWing);// 引擎粒子效果const engineParticles = this.createEngineParticles();engineParticles.position.set(0, -3, 0);shipGroup.add(engineParticles);shipGroup.position.set(...position);// 物理体const shape = new Cannon.Box(new Cannon.Vec3(3, 1.5, 3));const body = new Cannon.Body({mass: 1,material: this.materials.player,shape: shape});body.position.copy(shipGroup.position);this.world.addBody(body);shipGroup.userData = {id: playerId,type: 'player',physicsBody: body,health: 100,engineParticles: engineParticles};this.scene.add(shipGroup);this.players.set(playerId, shipGroup);return shipGroup;}// 创建引擎粒子效果createEngineParticles() {const particleCount = 50;const geometry = new THREE.BufferGeometry();const positions = new Float32Array(particleCount * 3);const colors = new Float32Array(particleCount * 3);const sizes = new Float32Array(particleCount);for (let i = 0; i < particleCount; i++) {const i3 = i * 3;positions[i3] = (Math.random() - 0.5) * 2;positions[i3 + 1] = Math.random() * -5;positions[i3 + 2] = (Math.random() - 0.5) * 2;colors[i3] = 1.0; // Rcolors[i3 + 1] = Math.random() * 0.5 + 0.5; // Gcolors[i3 + 2] = 0.0; // Bsizes[i] = Math.random() * 0.5 + 0.1;}geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));const material = new THREE.PointsMaterial({size: 1,sizeAttenuation: true,vertexColors: true,transparent: true,blending: THREE.AdditiveBlending});return new THREE.Points(geometry, material);}// 发射武器fireWeapon(playerId, targetDirection) {const player = this.players.get(playerId);if (!player) return;const startPosition = player.position.clone();startPosition.y -= 3; // 从飞船前端发射const projectile = this.createProjectile(startPosition, targetDirection);this.projectiles.add(projectile);// 设置自动销毁setTimeout(() => {this.destroyProjectile(projectile);}, 3000);}// 创建抛射物createProjectile(position, direction) {const geometry = new THREE.SphereGeometry(0.3, 8, 8);const material = new THREE.MeshBasicMaterial({color: 0xffff00,emissive: 0xffff00,emissiveIntensity: 0.8});const projectile = new THREE.Mesh(geometry, material);projectile.position.copy(position);// 物理体const shape = new Cannon.Sphere(0.3);const body = new Cannon.Body({mass: 0.1,material: this.materials.projectile,shape: shape});body.position.copy(position);body.velocity.set(direction.x * 50, direction.y * 50, direction.z * 50);this.world.addBody(body);projectile.userData.physicsBody = body;this.scene.add(projectile);return projectile;}// 销毁抛射物destroyProjectile(projectile) {if (projectile.parent) {projectile.parent.remove(projectile);}if (projectile.userData.physicsBody) {this.world.removeBody(projectile.userData.physicsBody);}this.projectiles.delete(projectile);}// 更新游戏状态update() {const deltaTime = this.clock.getDelta();// 更新物理世界this.world.step(1/60, deltaTime, 3);// 同步物理体和3D对象this.syncPhysicsWithGraphics();// 更新玩家输入this.updatePlayerInput(deltaTime);// 更新粒子效果this.updateParticleEffects(deltaTime);// 检测碰撞this.checkCollisions();// 渲染场景if (this.composer) {this.composer.render();} else {this.renderer.render(this.scene, this.camera);}}// 同步物理和图形syncPhysicsWithGraphics() {// 同步玩家this.players.forEach(player => {const body = player.userData.physicsBody;if (body) {player.position.copy(body.position);player.quaternion.copy(body.quaternion);}});// 同步抛射物this.projectiles.forEach(projectile => {const body = projectile.userData.physicsBody;if (body) {projectile.position.copy(body.position);}});// 同步游戏对象this.gameObjects.forEach(obj => {const body = obj.userData?.physicsBody;if (body) {obj.position.copy(body.position);obj.quaternion.copy(body.quaternion);}});}// 更新玩家输入updatePlayerInput(deltaTime) {const force = new Cannon.Vec3();const torque = new Cannon.Vec3();this.players.forEach(player => {const body = player.userData.physicsBody;if (!body) return;// 移动控制if (this.keys['KeyW']) force.z = -20;if (this.keys['KeyS']) force.z = 20;if (this.keys['KeyA']) force.x = -20;if (this.keys['KeyD']) force.x = 20;if (this.keys['Space']) force.y = 20;if (this.keys['ShiftLeft']) force.y = -20;// 应用力body.force = force;// 更新引擎粒子if (player.userData.engineParticles) {this.updateEngineParticles(player.userData.engineParticles, deltaTime);}});}// 更新引擎粒子updateEngineParticles(particles, deltaTime) {const positions = particles.geometry.attributes.position.array;const colors = particles.geometry.attributes.color.array;for (let i = 0; i < positions.length; i += 3) {// 粒子向下移动positions[i + 1] -= deltaTime * 10;// 如果粒子移出视野,重置位置if (positions[i + 1] < -5) {positions[i] = (Math.random() - 0.5) * 2;positions[i + 1] = 0;positions[i + 2] = (Math.random() - 0.5) * 2;}// 更新颜色强度const intensity = Math.random() * 0.5 + 0.5;colors[i] = 1.0; // Rcolors[i + 1] = intensity; // Gcolors[i + 2] = 0.0; // B}particles.geometry.attributes.position.needsUpdate = true;particles.geometry.attributes.color.needsUpdate = true;}// 检测碰撞checkCollisions() {// 简化的碰撞检测// 实际项目中应该使用更复杂的碰撞检测系统this.projectiles.forEach(projectile => {this.players.forEach(player => {if (projectile.userData.physicsBody && player.userData.physicsBody) {const distance = projectile.position.distanceTo(player.position);if (distance < 5) { // 碰撞距离阈值this.onProjectileHit(player, projectile);}}});});}// 抛射物命中处理onProjectileHit(player, projectile) {player.userData.health -= 10;this.destroyProjectile(projectile);// 触发命中效果this.createHitEffect(player.position);if (player.userData.health <= 0) {this.onPlayerDestroyed(player);}}// 创建命中效果createHitEffect(position) {// 创建爆炸粒子效果const particleCount = 20;const geometry = new THREE.BufferGeometry();const positions = new Float32Array(particleCount * 3);const velocities = new Float32Array(particleCount * 3);for (let i = 0; i < particleCount; i++) {const i3 = i * 3;positions[i3] = position.x;positions[i3 + 1] = position.y;positions[i3 + 2] = position.z;// 随机速度方向velocities[i3] = (Math.random() - 0.5) * 10;velocities[i3 + 1] = (Math.random() - 0.5) * 10;velocities[i3 + 2] = (Math.random() - 0.5) * 10;}geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));const material = new THREE.PointsMaterial({color: 0xff6600,size: 0.5,transparent: true,opacity: 0.8});const particles = new THREE.Points(geometry, material);particles.userData.velocities = velocities;particles.userData.lifetime = 0;this.scene.add(particles);// 动画更新const updateParticles = () => {particles.userData.lifetime += 0.016;if (particles.userData.lifetime > 1.0) {this.scene.remove(particles);return;}const positions = particles.geometry.attributes.position.array;const velocities = particles.userData.velocities;for (let i = 0; i < particleCount; i++) {const i3 = i * 3;positions[i3] += velocities[i3] * 0.016;positions[i3 + 1] += velocities[i3 + 1] * 0.016;positions[i3 + 2] += velocities[i3 + 2] * 0.016;}particles.geometry.attributes.position.needsUpdate = true;material.opacity = 1.0 - particles.userData.lifetime;requestAnimationFrame(updateParticles);};updateParticles();}// 玩家被摧毁onPlayerDestroyed(player) {// 创建大爆炸效果this.createExplosionEffect(player.position);// 移除玩家if (player.parent) {player.parent.remove(player);}if (player.userData.physicsBody) {this.world.removeBody(player.userData.physicsBody);}this.players.delete(player.userData.id);}// 创建爆炸效果createExplosionEffect(position) {// 创建爆炸球体const geometry = new THREE.SphereGeometry(5, 16, 16);const material = new THREE.MeshBasicMaterial({color: 0xff6600,transparent: true,opacity: 0.8});const explosion = new THREE.Mesh(geometry, material);explosion.position.copy(position);this.scene.add(explosion);// 爆炸动画const growExplosion = () => {explosion.scale.multiplyScalar(1.1);material.opacity *= 0.9;if (material.opacity < 0.1) {this.scene.remove(explosion);} else {requestAnimationFrame(growExplosion);}};growExplosion();}// 开始游戏循环start() {this.isRunning = true;this.gameLoop();}// 停止游戏stop() {this.isRunning = false;}// 游戏主循环gameLoop() {if (!this.isRunning) return;this.update();requestAnimationFrame(this.gameLoop.bind(this));}
}export default {name: 'StarExplorerGame',setup() {const gameCanvas = ref(null);const radarCanvas = ref(null);const showMenu = ref(true);const isLoading = ref(true);const loadingMessage = ref('初始化游戏引擎...');const loadingProgress = ref(0);const playerId = ref(1);const playerHealth = ref(100);const currentMission = ref('探索未知星系');const missionProgress = ref(25);const resources = reactive({fuel: 100,minerals: 0,parts: 5});const nearbyObjects = ref(3);const threatLevel = ref('低');const gameTime = ref(0);const explorationProgress = ref(15);const enemiesDefeated = ref(0);const isMultiplayer = ref(false);const onlinePlayers = ref(1);const graphicsQuality = ref('high');const soundVolume = ref(80);const enablePostProcessing = ref(true);let gameEngine = null;let gameInterval = null;// 初始化游戏const initGame = async () => {try {loadingMessage.value = '创建图形引擎...';loadingProgress.value = 20;gameEngine = new StarExplorerEngine(gameCanvas.value);await gameEngine.init();loadingMessage.value = '生成游戏世界...';loadingProgress.value = 60;// 创建玩家飞船gameEngine.createPlayerShip(playerId.value);loadingMessage.value = '完成初始化...';loadingProgress.value = 100;setTimeout(() => {isLoading.value = false;startGame();}, 1000);} catch (error) {console.error('游戏初始化失败:', error);loadingMessage.value = `初始化失败: ${error.message}`;}};// 开始游戏const startGame = () => {gameEngine.start();// 启动游戏计时器gameInterval = setInterval(() => {gameTime.value += 1;}, 1000);// 模拟游戏事件simulateGameEvents();};// 模拟游戏事件const simulateGameEvents = () => {setInterval(() => {// 随机更新附近物体数量nearbyObjects.value = Math.floor(Math.random() * 10) + 1;// 随机更新威胁等级const threats = ['低', '中', '高'];threatLevel.value = threats[Math.floor(Math.random() * threats.length)];// 缓慢增加探索进度if (explorationProgress.value < 100) {explorationProgress.value += 0.1;}}, 5000);};// 继续游戏const resumeGame = () => {showMenu.value = false;};// 重新开始游戏const restartGame = () => {if (gameEngine) {gameEngine.stop();}if (gameInterval) {clearInterval(gameInterval);}gameTime.value = 0;explorationProgress.value = 0;enemiesDefeated.value = 0;playerHealth.value = 100;showMenu.value = false;isLoading.value = true;setTimeout(() => {initGame();}, 1000);};// 退出游戏const exitGame = () => {if (gameEngine) {gameEngine.stop();}if (gameInterval) {clearInterval(gameInterval);}// 实际项目中这里应该跳转到其他页面或显示退出确认alert('感谢游玩星际探索者!');};// 切换多人游戏const toggleMultiplayer = () => {isMultiplayer.value = !isMultiplayer.value;onlinePlayers.value = isMultiplayer.value ? Math.floor(Math.random() * 10) + 2 : 1;};// 格式化游戏时间const formatGameTime = (seconds) => {const hours = Math.floor(seconds / 3600);const minutes = Math.floor((seconds % 3600) / 60);const secs = seconds % 60;return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;};// 计算样式const healthStyle = computed(() => ({width: `${playerHealth.value}%`}));const missionProgressStyle = computed(() => ({width: `${missionProgress.value}%`}));const loadingProgressStyle = computed(() => ({width: `${loadingProgress.value}%`}));onMounted(() => {initGame();});onUnmounted(() => {if (gameEngine) {gameEngine.stop();}if (gameInterval) {clearInterval(gameInterval);}});return {gameCanvas,radarCanvas,showMenu,isLoading,loadingMessage,loadingProgress,playerId,playerHealth,currentMission,missionProgress,resources,nearbyObjects,threatLevel,gameTime,explorationProgress,enemiesDefeated,isMultiplayer,onlinePlayers,graphicsQuality,soundVolume,enablePostProcessing,healthStyle,missionProgressStyle,loadingProgressStyle,resumeGame,restartGame,exitGame,toggleMultiplayer,formatGameTime};}
};
</script><style scoped>
.game-container {width: 100%;height: 100vh;position: relative;background: #000;overflow: hidden;
}.game-canvas {width: 100%;height: 100%;display: block;
}.hud-overlay {position: absolute;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;
}/* 顶部状态栏 */
.top-bar {position: absolute;top: 20px;left: 0;width: 100%;display: flex;justify-content: space-between;align-items: center;padding: 0 20px;color: white;
}.player-info {display: flex;flex-direction: column;align-items: flex-start;gap: 8px;
}.player-name {font-size: 18px;font-weight: bold;color: #00ffff;text-shadow: 0 0 10px #00ffff;
}.health-bar {width: 200px;height: 20px;background: rgba(255, 0, 0, 0.3);border: 2px solid #ff0000;border-radius: 10px;position: relative;overflow: hidden;
}.health-fill {height: 100%;background: linear-gradient(90deg, #ff0000, #ffff00);border-radius: 8px;transition: width 0.3s ease;
}.health-text {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);font-size: 12px;font-weight: bold;color: white;text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
}.mission-info {display: flex;flex-direction: column;align-items: center;gap: 8px;
}.mission-info h3 {margin: 0;color: #00ff88;font-size: 16px;
}.mission-progress {width: 300px;height: 10px;background: rgba(0, 255, 136, 0.3);border-radius: 5px;overflow: hidden;
}.progress-fill {height: 100%;background: linear-gradient(90deg, #00ff88, #00aaff);border-radius: 5px;transition: width 0.5s ease;
}.resource-display {display: flex;gap: 20px;
}.resource-item {display: flex;align-items: center;gap: 8px;padding: 8px 12px;background: rgba(0, 0, 0, 0.6);border: 1px solid #00aaff;border-radius: 8px;
}.resource-icon {font-size: 16px;
}.resource-value {font-size: 16px;font-weight: bold;color: #00aaff;
}/* 雷达显示 */
.radar-container {position: absolute;bottom: 100px;right: 20px;display: flex;flex-direction: column;align-items: center;gap: 10px;
}.radar-display {width: 150px;height: 150px;background: rgba(0, 0, 0, 0.7);border: 2px solid #00ffff;border-radius: 50%;position: relative;overflow: hidden;
}.radar-canvas {width: 100%;height: 100%;
}.radar-info {display: flex;flex-direction: column;align-items: center;gap: 5px;color: #00ffff;font-size: 12px;
}/* 控制提示 */
.control-hints {position: absolute;bottom: 20px;left: 20px;display: flex;gap: 20px;
}.hint-group {display: flex;align-items: center;gap: 8px;padding: 8px 12px;background: rgba(0, 0, 0, 0.6);border: 1px solid #00aaff;border-radius: 6px;color: white;
}.hint-group kbd {padding: 4px 8px;background: #00aaff;color: black;border-radius: 4px;font-family: monospace;font-weight: bold;
}/* 游戏菜单 */
.game-menu {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: rgba(0, 0, 0, 0.8);display: flex;justify-content: center;align-items: center;z-index: 1000;
}.menu-content {background: linear-gradient(135deg, #0a0a2a, #1a1a4a);border: 2px solid #00ffff;border-radius: 15px;padding: 40px;max-width: 600px;width: 90%;color: white;text-align: center;
}.menu-content h1 {color: #00ffff;font-size: 3em;margin-bottom: 30px;text-shadow: 0 0 20px #00ffff;
}.menu-section {margin-bottom: 25px;text-align: left;
}.menu-section h2 {color: #00ff88;border-bottom: 1px solid #00ff88;padding-bottom: 8px;margin-bottom: 15px;
}.menu-stats {display: flex;flex-direction: column;gap: 8px;
}.stat-item {display: flex;justify-content: space-between;padding: 5px 0;
}.multiplayer-controls {display: flex;flex-direction: column;gap: 10px;
}.players-online {color: #00aaff;font-style: italic;
}.settings-controls {display: flex;flex-direction: column;gap: 12px;
}.setting-item {display: flex;justify-content: space-between;align-items: center;padding: 5px 0;
}.setting-item select,
.setting-item input[type="range"] {background: #2a2a5a;border: 1px solid #00aaff;border-radius: 4px;color: white;padding: 5px;
}.menu-actions {display: flex;justify-content: center;gap: 15px;margin-top: 30px;
}.menu-button {padding: 12px 24px;border: 2px solid #00aaff;border-radius: 8px;background: rgba(0, 170, 255, 0.2);color: white;font-size: 16px;cursor: pointer;transition: all 0.3s ease;
}.menu-button:hover {background: rgba(0, 170, 255, 0.4);transform: translateY(-2px);
}.menu-button.primary {background: rgba(0, 255, 136, 0.3);border-color: #00ff88;
}.menu-button.danger {background: rgba(255, 0, 0, 0.3);border-color: #ff0000;
}.menu-button.active {background: rgba(0, 170, 255, 0.6);
}/* 加载界面 */
.loading-screen {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background: #000;display: flex;justify-content: center;align-items: center;z-index: 2000;
}.loading-content {text-align: center;color: white;
}.loading-animation {position: relative;width: 100px;height: 100px;margin: 0 auto 30px;
}.spaceship-loader {width: 40px;height: 40px;border: 3px solid #00ffff;border-top: 3px solid transparent;border-radius: 50%;animation: spin 1s linear infinite;margin: 0 auto;
}.loading-particles {position: absolute;top: 0;left: 0;width: 100%;height: 100%;
}.loading-particles::before,
.loading-particles::after {content: '';position: absolute;width: 8px;height: 8px;background: #00ffff;border-radius: 50%;animation: float 2s ease-in-out infinite;
}.loading-particles::before {top: 10px;left: 20px;animation-delay: 0s;
}.loading-particles::after {bottom: 10px;right: 20px;animation-delay: 1s;
}.loading-content h2 {color: #00ffff;margin-bottom: 20px;
}.loading-progress {width: 300px;margin: 0 auto;
}.progress-bar {width: 100%;height: 6px;background: rgba(255, 255, 255, 0.1);border-radius: 3px;overflow: hidden;margin-bottom: 10px;
}.progress-text {color: #00aaff;font-size: 14px;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}@keyframes float {0%, 100% { transform: translateY(0) scale(1); opacity: 1; }50% { transform: translateY(-20px) scale(1.2); opacity: 0.7; }
}
</style>

技术亮点总结

1. 综合技术应用

  • 图形渲染: Three.js + 后期处理实现电影级视觉效果
  • 物理仿真: Cannon-es物理引擎提供真实交互体验
  • 网络同步: WebSocket实现多人实时交互
  • 性能优化: LOD系统 + 实例化渲染确保流畅体验

2. 游戏架构设计

  • 模块化设计: 引擎、逻辑、渲染分离
  • 事件驱动: 基于事件的游戏逻辑处理
  • 状态管理: 统一的游戏状态管理机制
  • 资源管理: 智能资源加载和缓存系统

3. 用户体验优化

  • 直观HUD: 清晰的状态信息和操作提示
  • 流畅动画: 粒子效果和过渡动画增强沉浸感
  • 自适应控制: 支持键盘、鼠标等多种输入方式
  • 性能自适应: 根据设备性能动态调整画质

扩展建议

后续开发方向

  1. AI系统: 添加NPC敌人和友方单位
  2. 任务系统: 设计丰富的任务和成就系统
  3. 经济系统: 实现资源交易和升级机制
  4. 社交功能: 添加好友系统和公会功能

性能优化空间

  1. WebAssembly: 使用Rust/C++编写性能关键模块
  2. 服务端渲染: 实现服务器端的世界状态管理
  3. 预测算法: 优化网络同步的预测和调和算法
  4. 内存管理: 实现更精细的内存使用控制

这个游戏原型展示了Three.js在复杂3D应用开发中的强大能力,为后续的商业级游戏开发奠定了坚实基础。

http://www.dtcms.com/a/462365.html

相关文章:

  • 设计的有趣的网站推荐怎样申请免费网站域名
  • --- 前后端的文件交互 ---
  • 打工人日报#20251009
  • 高并发秒杀系统设计:从理论到实践
  • Java 定时任务
  • 如何创建网站的二维码如何编辑 wordpress 主题
  • C++内存模型深度剖析从并发编程到原子操作的内存序语义
  • seo优化方法有哪些
  • 土动三轴试验机技术指标
  • 漳州正规网站建设公司wordpress google插件
  • 营销网站首页设计wordpress 博客主题
  • 鸿蒙路上的那些事:从初学者到资源创作者
  • 河北网站开发联系电话4a网站建设公司
  • 在 VS Code 中让整个工作区只读
  • 优秀网站菜单wordpress注册收不到邮件
  • 合肥网站建设pqiw目录网站做外链
  • 泉州自主建站模板网站设计费用价目表
  • 让水分子“导航”,突破蛋白–糖类分子对接难题
  • 在dify工作流中如何定义filename自动生成
  • asp 网站后台免费的企业网页制作网站
  • ILSpy下载和安装教程(附安装包,图文并茂)
  • 微信小程序-9-上滑加载更多和下拉刷新及小程序更新分享和转发
  • 【AES加密专题】1.AES的原理详解和加密过程
  • hello_servlet
  • 易拉罐和瓶子分类数据集 6059张图片,支持yolo,coco json,paschal voc xml格式,识别率可达92.5%,文末提供下载地址
  • 1 玩转Linux命令行:基础文件操作实战教程
  • 图观 流渲染打包服务器
  • 为什么只有中国做网站需要备案建站技术博客
  • 最好的微网站建设价格搜索引擎排名国内
  • 自动化测试中元素定位失败的解决策略