Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>太空射击 - 3D 射击游戏</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/effects/OutlineEffect.js"></script> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
font-family: 'Arial', sans-serif; | |
} | |
#game-container { | |
position: relative; | |
width: 100vw; | |
height: 100vh; | |
} | |
#ui-overlay { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
pointer-events: none; | |
color: white; | |
font-family: 'Orbitron', sans-serif; | |
} | |
#health-bar { | |
position: absolute; | |
top: 20px; | |
left: 20px; | |
width: 200px; | |
height: 20px; | |
background-color: rgba(255, 0, 0, 0.3); | |
border: 2px solid white; | |
border-radius: 5px; | |
overflow: hidden; | |
} | |
#health-fill { | |
height: 100%; | |
width: 100%; | |
background-color: #ff3366; | |
transition: width 0.3s; | |
} | |
#score { | |
position: absolute; | |
top: 20px; | |
right: 20px; | |
font-size: 24px; | |
color: white; | |
text-shadow: 0 0 10px #00ffff; | |
} | |
#level { | |
position: absolute; | |
top: 60px; | |
right: 20px; | |
font-size: 18px; | |
color: white; | |
text-shadow: 0 0 5px #00ffff; | |
} | |
#ammo { | |
position: absolute; | |
bottom: 20px; | |
left: 20px; | |
font-size: 18px; | |
color: white; | |
text-shadow: 0 0 5px #00ffff; | |
} | |
#game-over, #level-complete, #start-screen { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
display: flex; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
background-color: rgba(0, 0, 0, 0.8); | |
color: white; | |
font-size: 36px; | |
pointer-events: auto; | |
} | |
.button { | |
margin-top: 20px; | |
padding: 10px 30px; | |
background: linear-gradient(45deg, #ff3366, #00ffff); | |
border: none; | |
border-radius: 5px; | |
color: white; | |
font-size: 18px; | |
cursor: pointer; | |
pointer-events: auto; | |
transition: all 0.3s; | |
} | |
.button:hover { | |
transform: scale(1.05); | |
box-shadow: 0 0 15px #00ffff; | |
} | |
#enemy-count { | |
position: absolute; | |
top: 60px; | |
left: 20px; | |
font-size: 18px; | |
color: white; | |
text-shadow: 0 0 5px #00ffff; | |
} | |
#boss-health { | |
position: absolute; | |
top: 100px; | |
left: 50%; | |
transform: translateX(-50%); | |
width: 300px; | |
height: 20px; | |
background-color: rgba(255, 0, 0, 0.3); | |
border: 2px solid white; | |
border-radius: 5px; | |
overflow: hidden; | |
display: none; | |
} | |
#boss-health-fill { | |
height: 100%; | |
width: 100%; | |
background-color: #ff3366; | |
transition: width 0.3s; | |
} | |
#power-ups { | |
position: absolute; | |
bottom: 60px; | |
left: 20px; | |
display: flex; | |
gap: 10px; | |
} | |
.power-up-icon { | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
font-size: 20px; | |
background-color: rgba(255, 255, 255, 0.2); | |
border: 2px solid white; | |
} | |
#crosshair { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
width: 30px; | |
height: 30px; | |
pointer-events: none; | |
} | |
#crosshair::before, #crosshair::after { | |
content: ''; | |
position: absolute; | |
background-color: rgba(255, 255, 255, 0.8); | |
} | |
#crosshair::before { | |
width: 30px; | |
height: 2px; | |
left: 0; | |
top: 14px; | |
} | |
#crosshair::after { | |
width: 2px; | |
height: 30px; | |
left: 14px; | |
top: 0; | |
} | |
#crosshair.active { | |
animation: pulse 0.5s infinite alternate; | |
} | |
@keyframes pulse { | |
from { transform: translate(-50%, -50%) scale(1); } | |
to { transform: translate(-50%, -50%) scale(1.2); } | |
} | |
#radar { | |
position: absolute; | |
bottom: 20px; | |
right: 20px; | |
width: 150px; | |
height: 150px; | |
border-radius: 50%; | |
background-color: rgba(0, 0, 0, 0.5); | |
border: 2px solid #00ffff; | |
overflow: hidden; | |
} | |
#radar-center { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
width: 2px; | |
height: 2px; | |
border-radius: 50%; | |
background-color: #00ffff; | |
} | |
.radar-sweep { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border-radius: 50%; | |
clip-path: polygon(50% 50%, 50% 0, 50% 0); | |
background-color: rgba(0, 255, 255, 0.2); | |
animation: radarSweep 3s linear infinite; | |
} | |
@keyframes radarSweep { | |
from { transform: rotate(0deg); } | |
to { transform: rotate(360deg); } | |
} | |
.radar-blip { | |
position: absolute; | |
width: 6px; | |
height: 6px; | |
border-radius: 50%; | |
background-color: #ff3366; | |
transform: translate(-50%, -50%); | |
} | |
</style> | |
</head> | |
<body> | |
<div id="game-container"> | |
<div id="ui-overlay"> | |
<div id="health-bar"> | |
<div id="health-fill"></div> | |
</div> | |
<div id="score">分数: 0</div> | |
<div id="level">关卡: 1</div> | |
<div id="enemy-count">敌人: 0</div> | |
<div id="boss-health"> | |
<div id="boss-health-fill"></div> | |
</div> | |
<div id="ammo">弹药: ∞</div> | |
<div id="power-ups"></div> | |
<div id="crosshair"></div> | |
<div id="radar"> | |
<div id="radar-center"></div> | |
<div class="radar-sweep"></div> | |
</div> | |
<div id="start-screen"> | |
<h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-600">太空射击</h1> | |
<p class="text-xl mb-8">保卫银河系免受外星入侵</p> | |
<button id="start-button" class="button">开始游戏</button> | |
<div class="mt-8 text-sm"> | |
<p>控制方式: WASD移动, 鼠标瞄准射击</p> | |
<p>空格键: 特殊武器</p> | |
</div> | |
</div> | |
<div id="game-over" style="display: none;"> | |
<h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-red-400 to-purple-600">游戏结束</h1> | |
<p class="text-xl mb-4">最终分数: <span id="final-score">0</span></p> | |
<p class="text-xl mb-8">最高关卡: <span id="final-level">1</span></p> | |
<button id="restart-button" class="button">重新开始</button> | |
</div> | |
<div id="level-complete" style="display: none;"> | |
<h1 class="text-5xl font-bold mb-8 text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-blue-600">关卡完成!</h1> | |
<p class="text-xl mb-4">分数: <span id="level-score">0</span></p> | |
<p class="text-xl mb-8">下一关卡: <span id="next-level">2</span></p> | |
<button id="next-level-button" class="button">继续</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
// 游戏常量 | |
const GAME = { | |
WIDTH: window.innerWidth, | |
HEIGHT: window.innerHeight, | |
ASPECT: window.innerWidth / window.innerHeight, | |
NEAR: 0.1, | |
FAR: 10000, | |
FOV: 75, | |
PLAYER_SPEED: 0.3, | |
BULLET_SPEED: 1.5, | |
ENEMY_SPEED: 0.1, | |
BOSS_SPEED: 0.05, | |
POWERUP_DURATION: 10000, // 10秒 | |
LEVELS: [ | |
{ enemies: 10, enemyHealth: 1, spawnRate: 1000, boss: false }, | |
{ enemies: 15, enemyHealth: 2, spawnRate: 800, boss: false }, | |
{ enemies: 20, enemyHealth: 3, spawnRate: 600, boss: false }, | |
{ enemies: 25, enemyHealth: 4, spawnRate: 500, boss: true }, | |
{ enemies: 30, enemyHealth: 5, spawnRate: 400, boss: false }, | |
{ enemies: 35, enemyHealth: 6, spawnRate: 300, boss: false }, | |
{ enemies: 40, enemyHealth: 7, spawnRate: 200, boss: true }, | |
{ enemies: 50, enemyHealth: 8, spawnRate: 100, boss: true } | |
] | |
}; | |
// 游戏状态 | |
let gameState = { | |
score: 0, | |
level: 1, | |
health: 100, | |
maxHealth: 100, | |
ammo: Infinity, | |
gameOver: false, | |
levelComplete: false, | |
enemies: [], | |
bullets: [], | |
enemyBullets: [], | |
powerUps: [], | |
activePowerUps: {}, | |
boss: null, | |
bossActive: false, | |
enemiesSpawned: 0, | |
enemiesDestroyed: 0, | |
lastShot: 0, | |
shotDelay: 200, | |
lastEnemyShot: 0, | |
enemyShotDelay: 1000, | |
lastPowerUpSpawn: 0, | |
powerUpSpawnDelay: 15000, | |
specialWeaponReady: true, | |
specialWeaponCooldown: 10000, | |
lastSpecialWeaponUse: 0 | |
}; | |
// Three.js 变量 | |
let scene, camera, renderer, controls, effect; | |
let player, playerGroup; | |
let clock = new THREE.Clock(); | |
let raycaster = new THREE.Raycaster(); | |
let mouse = new THREE.Vector2(); | |
let isMouseDown = false; | |
let keys = {}; | |
let radarBlips = []; | |
// 初始化游戏 | |
function init() { | |
// 创建场景 | |
scene = new THREE.Scene(); | |
scene.background = new THREE.Color(0x000000); | |
scene.fog = new THREE.FogExp2(0x000000, 0.0005); | |
// 创建相机 | |
camera = new THREE.PerspectiveCamera(GAME.FOV, GAME.ASPECT, GAME.NEAR, GAME.FAR); | |
camera.position.set(0, 5, 15); | |
camera.lookAt(0, 0, 0); | |
// 创建渲染器 | |
renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(GAME.WIDTH, GAME.HEIGHT); | |
renderer.shadowMap.enabled = true; | |
document.getElementById('game-container').appendChild(renderer.domElement); | |
// 添加轮廓效果 | |
effect = new THREE.OutlineEffect(renderer); | |
// 添加灯光 | |
addLights(); | |
// 添加星空背景 | |
createStarfield(); | |
// 创建玩家飞船 | |
createPlayer(); | |
// 添加事件监听器 | |
setupEventListeners(); | |
// 显示开始屏幕 | |
document.getElementById('start-screen').style.display = 'flex'; | |
// 开始游戏循环 | |
animate(); | |
} | |
// 添加灯光 | |
function addLights() { | |
// 环境光 | |
const ambientLight = new THREE.AmbientLight(0x404040); | |
scene.add(ambientLight); | |
// 方向光 | |
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); | |
directionalLight.position.set(1, 1, 1); | |
directionalLight.castShadow = true; | |
directionalLight.shadow.mapSize.width = 1024; | |
directionalLight.shadow.mapSize.height = 1024; | |
scene.add(directionalLight); | |
// 点光源 | |
const pointLight = new THREE.PointLight(0x00ffff, 2, 50); | |
pointLight.position.set(0, 5, 0); | |
scene.add(pointLight); | |
// 聚光灯 | |
const spotLight = new THREE.SpotLight(0xffffff, 1); | |
spotLight.position.set(0, 10, 0); | |
spotLight.castShadow = true; | |
spotLight.shadow.mapSize.width = 1024; | |
spotLight.shadow.mapSize.height = 1024; | |
scene.add(spotLight); | |
} | |
// 创建星空背景 | |
function createStarfield() { | |
const starGeometry = new THREE.BufferGeometry(); | |
const starMaterial = new THREE.PointsMaterial({ | |
color: 0xffffff, | |
size: 0.1, | |
transparent: true, | |
opacity: 0.8 | |
}); | |
const stars = []; | |
for (let i = 0; i < 5000; i++) { | |
const x = (Math.random() - 0.5) * 2000; | |
const y = (Math.random() - 0.5) * 2000; | |
const z = (Math.random() - 0.5) * 2000; | |
stars.push(x, y, z); | |
} | |
starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(stars, 3)); | |
const starField = new THREE.Points(starGeometry, starMaterial); | |
scene.add(starField); | |
} | |
// 创建玩家飞船 | |
function createPlayer() { | |
playerGroup = new THREE.Group(); | |
// 创建飞船主体 | |
const geometry = new THREE.ConeGeometry(0.5, 1.5, 4); | |
const material = new THREE.MeshPhongMaterial({ | |
color: 0x3366ff, | |
emissive: 0x0044cc, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
player = new THREE.Mesh(geometry, material); | |
player.rotation.x = Math.PI / 2; | |
player.position.y = 0.5; | |
player.castShadow = true; | |
// 添加引擎火焰 | |
const flameGeometry = new THREE.ConeGeometry(0.3, 1, 4); | |
const flameMaterial = new THREE.MeshBasicMaterial({ | |
color: 0xff6600, | |
transparent: true, | |
opacity: 0.8 | |
}); | |
const flame = new THREE.Mesh(flameGeometry, flameMaterial); | |
flame.rotation.x = Math.PI / 2; | |
flame.position.z = -1; | |
player.add(flame); | |
// 添加机翼 | |
const wingGeometry = new THREE.BoxGeometry(1, 0.1, 0.5); | |
const wingMaterial = new THREE.MeshPhongMaterial({ | |
color: 0x3366ff, | |
emissive: 0x0044cc, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); | |
leftWing.position.set(-0.8, 0, 0); | |
player.add(leftWing); | |
const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); | |
rightWing.position.set(0.8, 0, 0); | |
player.add(rightWing); | |
playerGroup.add(player); | |
playerGroup.position.set(0, 0, -10); | |
scene.add(playerGroup); | |
} | |
// 创建敌人 | |
function createEnemy(x, y, z, health = 1) { | |
const enemyGroup = new THREE.Group(); | |
// 创建敌人主体 | |
const geometry = new THREE.OctahedronGeometry(0.6); | |
const material = new THREE.MeshPhongMaterial({ | |
color: health > 3 ? 0xff0000 : (health > 1 ? 0xff9900 : 0x00ff00), | |
emissive: health > 3 ? 0x990000 : (health > 1 ? 0x994400 : 0x009900), | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
const enemy = new THREE.Mesh(geometry, material); | |
enemy.castShadow = true; | |
enemy.userData.health = health; | |
enemy.userData.maxHealth = health; | |
// 添加细节 | |
const eyeGeometry = new THREE.SphereGeometry(0.1); | |
const eyeMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 }); | |
const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
leftEye.position.set(-0.2, 0.2, 0.5); | |
enemy.add(leftEye); | |
const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
rightEye.position.set(0.2, 0.2, 0.5); | |
enemy.add(rightEye); | |
enemyGroup.add(enemy); | |
enemyGroup.position.set(x, y, z); | |
enemyGroup.userData.speed = GAME.ENEMY_SPEED * (1 + Math.random() * 0.5); | |
enemyGroup.userData.isBoss = false; | |
scene.add(enemyGroup); | |
gameState.enemies.push(enemyGroup); | |
return enemyGroup; | |
} | |
// 创建Boss敌人 | |
function createBoss() { | |
const bossGroup = new THREE.Group(); | |
// 创建Boss主体 | |
const geometry = new THREE.DodecahedronGeometry(2); | |
const material = new THREE.MeshPhongMaterial({ | |
color: 0xff0000, | |
emissive: 0x990000, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
const boss = new THREE.Mesh(geometry, material); | |
boss.castShadow = true; | |
boss.userData.health = 20; | |
boss.userData.maxHealth = 20; | |
// 添加细节 | |
const eyeGeometry = new THREE.SphereGeometry(0.3); | |
const eyeMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 }); | |
const leftEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
leftEye.position.set(-0.8, 0.5, 1.8); | |
boss.add(leftEye); | |
const rightEye = new THREE.Mesh(eyeGeometry, eyeMaterial); | |
rightEye.position.set(0.8, 0.5, 1.8); | |
boss.add(rightEye); | |
// 添加武器 | |
const weaponGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1, 6); | |
const weaponMaterial = new THREE.MeshPhongMaterial({ | |
color: 0x666666, | |
emissive: 0x333333, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
const leftWeapon = new THREE.Mesh(weaponGeometry, weaponMaterial); | |
leftWeapon.position.set(-1.5, 0, 0); | |
leftWeapon.rotation.z = Math.PI / 2; | |
boss.add(leftWeapon); | |
const rightWeapon = new THREE.Mesh(weaponGeometry, weaponMaterial); | |
rightWeapon.position.set(1.5, 0, 0); | |
rightWeapon.rotation.z = Math.PI / 2; | |
boss.add(rightWeapon); | |
bossGroup.add(boss); | |
bossGroup.position.set(0, 0, 50); | |
bossGroup.userData.speed = GAME.BOSS_SPEED; | |
bossGroup.userData.isBoss = true; | |
bossGroup.userData.lastShot = 0; | |
bossGroup.userData.shotDelay = 500; | |
scene.add(bossGroup); | |
gameState.enemies.push(bossGroup); | |
gameState.boss = bossGroup; | |
gameState.bossActive = true; | |
// 显示Boss血条 | |
document.getElementById('boss-health').style.display = 'block'; | |
updateBossHealth(); | |
return bossGroup; | |
} | |
// 创建子弹 | |
function createBullet(x, y, z, isEnemy = false) { | |
const bulletGroup = new THREE.Group(); | |
const geometry = new THREE.SphereGeometry(0.1); | |
const material = new THREE.MeshPhongMaterial({ | |
color: isEnemy ? 0xff0000 : 0x00ffff, | |
emissive: isEnemy ? 0x990000 : 0x006666, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true | |
}); | |
const bullet = new THREE.Mesh(geometry, material); | |
bullet.castShadow = true; | |
// 添加光晕效果 | |
const glowGeometry = new THREE.SphereGeometry(0.2); | |
const glowMaterial = new THREE.MeshBasicMaterial({ | |
color: isEnemy ? 0xff0000 : 0x00ffff, | |
transparent: true, | |
opacity: 0.5 | |
}); | |
const glow = new THREE.Mesh(glowGeometry, glowMaterial); | |
bullet.add(glow); | |
bulletGroup.add(bullet); | |
bulletGroup.position.set(x, y, z); | |
bulletGroup.userData.isEnemy = isEnemy; | |
bulletGroup.userData.speed = isEnemy ? GAME.BULLET_SPEED * 0.8 : GAME.BULLET_SPEED; | |
scene.add(bulletGroup); | |
if (isEnemy) { | |
gameState.enemyBullets.push(bulletGroup); | |
} else { | |
gameState.bullets.push(bulletGroup); | |
} | |
return bulletGroup; | |
} | |
// 创建能量道具 | |
function createPowerUp(x, y, z) { | |
const powerUpGroup = new THREE.Group(); | |
const geometry = new THREE.IcosahedronGeometry(0.4); | |
const material = new THREE.MeshPhongMaterial({ | |
color: 0xffff00, | |
emissive: 0x996600, | |
specular: 0xffffff, | |
shininess: 30, | |
flatShading: true, | |
transparent: true, | |
opacity: 0.9 | |
}); | |
const powerUp = new THREE.Mesh(geometry, material); | |
powerUp.castShadow = true; | |
// 随机选择道具类型 | |
const types = ['health', 'shield', 'speed', 'fireRate', 'special']; | |
const type = types[Math.floor(Math.random() * types.length)]; | |
powerUp.userData.type = type; | |
// 根据类型改变颜色 | |
switch (type) { | |
case 'health': | |
powerUp.material.color.setHex(0x00ff00); | |
powerUp.material.emissive.setHex(0x009900); | |
break; | |
case 'shield': | |
powerUp.material.color.setHex(0x3366ff); | |
powerUp.material.emissive.setHex(0x003399); | |
break; | |
case 'speed': | |
powerUp.material.color.setHex(0xff9900); | |
powerUp.material.emissive.setHex(0x994400); | |
break; | |
case 'fireRate': | |
powerUp.material.color.setHex(0xff00ff); | |
powerUp.material.emissive.setHex(0x990099); | |
break; | |
case 'special': | |
powerUp.material.color.setHex(0xff0000); | |
powerUp.material.emissive.setHex(0x990000); | |
break; | |
} | |
powerUpGroup.add(powerUp); | |
powerUpGroup.position.set(x, y, z); | |
powerUpGroup.userData.speed = 0.05; | |
scene.add(powerUpGroup); | |
gameState.powerUps.push(powerUpGroup); | |
return powerUpGroup; | |
} | |
// 设置事件监听器 | |
function setupEventListeners() { | |
// 鼠标移动 | |
window.addEventListener('mousemove', (event) => { | |
mouse.x = (event.clientX / GAME.WIDTH) * 2 - 1; | |
mouse.y = -(event.clientY / GAME.HEIGHT) * 2 + 1; | |
}); | |
// 鼠标按下 | |
window.addEventListener('mousedown', () => { | |
isMouseDown = true; | |
document.getElementById('crosshair').classList.add('active'); | |
}); | |
// 鼠标释放 | |
window.addEventListener('mouseup', () => { | |
isMouseDown = false; | |
document.getElementById('crosshair').classList.remove('active'); | |
}); | |
// 键盘按下 | |
window.addEventListener('keydown', (event) => { | |
keys[event.code] = true; | |
// 空格键发射特殊武器 | |
if (event.code === 'Space' && gameState.specialWeaponReady) { | |
fireSpecialWeapon(); | |
} | |
}); | |
// 键盘释放 | |
window.addEventListener('keyup', (event) => { | |
keys[event.code] = false; | |
}); | |
// 窗口大小调整 | |
window.addEventListener('resize', () => { | |
GAME.WIDTH = window.innerWidth; | |
GAME.HEIGHT = window.innerHeight; | |
GAME.ASPECT = GAME.WIDTH / GAME.HEIGHT; | |
camera.aspect = GAME.ASPECT; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(GAME.WIDTH, GAME.HEIGHT); | |
}); | |
// 开始按钮 | |
document.getElementById('start-button').addEventListener('click', startGame); | |
// 重新开始按钮 | |
document.getElementById('restart-button').addEventListener('click', restartGame); | |
// 下一关按钮 | |
document.getElementById('next-level-button').addEventListener('click', nextLevel); | |
} | |
// 开始游戏 | |
function startGame() { | |
document.getElementById('start-screen').style.display = 'none'; | |
gameState = { | |
score: 0, | |
level: 1, | |
health: 100, | |
maxHealth: 100, | |
ammo: Infinity, | |
gameOver: false, | |
levelComplete: false, | |
enemies: [], | |
bullets: [], | |
enemyBullets: [], | |
powerUps: [], | |
activePowerUps: {}, | |
boss: null, | |
bossActive: false, | |
enemiesSpawned: 0, | |
enemiesDestroyed: 0, | |
lastShot: 0, | |
shotDelay: 200, | |
lastEnemyShot: 0, | |
enemyShotDelay: 1000, | |
lastPowerUpSpawn: 0, | |
powerUpSpawnDelay: 15000, | |
specialWeaponReady: true, | |
specialWeaponCooldown: 10000, | |
lastSpecialWeaponUse: 0 | |
}; | |
updateUI(); | |
spawnEnemies(); | |
} | |
// 重新开始游戏 | |
function restartGame() { | |
document.getElementById('game-over').style.display = 'none'; | |
// 清除所有游戏对象 | |
clearGameObjects(); | |
// 重置玩家位置 | |
playerGroup.position.set(0, 0, -10); | |
startGame(); | |
} | |
// 下一关 | |
function nextLevel() { | |
document.getElementById('level-complete').style.display = 'none'; | |
// 清除所有游戏对象 | |
clearGameObjects(); | |
// 重置玩家位置 | |
playerGroup.position.set(0, 0, -10); | |
// 增加关卡 | |
gameState.level++; | |
gameState.enemiesSpawned = 0; | |
gameState.enemiesDestroyed = 0; | |
gameState.bossActive = false; | |
gameState.boss = null; | |
updateUI(); | |
spawnEnemies(); | |
} | |
// 清除所有游戏对象 | |
function clearGameObjects() { | |
// 清除敌人 | |
gameState.enemies.forEach(enemy => { | |
scene.remove(enemy); | |
}); | |
gameState.enemies = []; | |
// 清除子弹 | |
gameState.bullets.forEach(bullet => { | |
scene.remove(bullet); | |
}); | |
gameState.bullets = []; | |
// 清除敌人子弹 | |
gameState.enemyBullets.forEach(bullet => { | |
scene.remove(bullet); | |
}); | |
gameState.enemyBullets = []; | |
// 清除能量道具 | |
gameState.powerUps.forEach(powerUp => { | |
scene.remove(powerUp); | |
}); | |
gameState.powerUps = []; | |
// 清除雷达标记 | |
radarBlips.forEach(blip => { | |
if (blip.parentNode) { | |
blip.parentNode.removeChild(blip); | |
} | |
}); | |
radarBlips = []; | |
// 隐藏Boss血条 | |
document.getElementById('boss-health').style.display = 'none'; | |
} | |
// 生成敌人 | |
function spawnEnemies() { | |
const currentLevel = Math.min(gameState.level - 1, GAME.LEVELS.length - 1); | |
const levelData = GAME.LEVELS[currentLevel]; | |
// 设置敌人生成间隔 | |
const spawnInterval = setInterval(() => { | |
if (gameState.enemiesSpawned >= levelData.enemies) { | |
clearInterval(spawnInterval); | |
// 如果是Boss关卡且所有小敌人都被消灭,生成Boss | |
if (levelData.boss && gameState.enemiesDestroyed >= levelData.enemies && !gameState.bossActive) { | |
createBoss(); | |
} | |
return; | |
} | |
// 随机生成敌人位置 | |
const x = (Math.random() - 0.5) * 30; | |
const y = (Math.random() - 0.5) * 10; | |
const z = 50 + Math.random() * 50; | |
createEnemy(x, y, z, levelData.enemyHealth); | |
gameState.enemiesSpawned++; | |
updateUI(); | |
}, levelData.spawnRate); | |
} | |
// 发射子弹 | |
function fireBullet() { | |
const now = Date.now(); | |
if (now - gameState.lastShot < gameState.shotDelay) return; | |
// 计算射击延迟(如果有火力增强道具) | |
const fireRatePower = gameState.activePowerUps['fireRate']; | |
const actualShotDelay = fireRatePower ? gameState.shotDelay * 0.5 : gameState.shotDelay; | |
if (now - gameState.lastShot < actualShotDelay) return; | |
gameState.lastShot = now; | |
// 从玩家位置发射子弹 | |
const bullet = createBullet( | |
playerGroup.position.x, | |
playerGroup.position.y, | |
playerGroup.position.z + 1 | |
); | |
// 设置子弹方向(朝向鼠标指向的位置) | |
raycaster.setFromCamera(mouse, camera); | |
const direction = raycaster.ray.direction.clone(); | |
direction.multiplyScalar(100); | |
bullet.userData.direction = direction.normalize(); | |
// 播放射击音效(这里可以添加音效) | |
} | |
// 发射特殊武器 | |
function fireSpecialWeapon() { | |
const now = Date.now(); | |
if (!gameState.specialWeaponReady || now - gameState.lastSpecialWeaponUse < gameState.specialWeaponCooldown) return; | |
gameState.specialWeaponReady = false; | |
gameState.lastSpecialWeaponUse = now; | |
// 创建多个子弹形成扇形攻击 | |
const bulletCount = 10; | |
for (let i = 0; i < bulletCount; i++) { | |
setTimeout(() => { | |
const angle = (i / bulletCount) * Math.PI - Math.PI / 2; | |
const bullet = createBullet( | |
playerGroup.position.x, | |
playerGroup.position.y, | |
playerGroup.position.z + 1 | |
); | |
// 设置子弹方向(扇形分布) | |
const direction = new THREE.Vector3( | |
Math.sin(angle) * 0.5, | |
0, | |
1 | |
).normalize(); | |
bullet.userData.direction = direction; | |
bullet.userData.speed = GAME.BULLET_SPEED * 1.5; | |
// 特殊武器的子弹更大 | |
bullet.children[0].scale.set(2, 2, 2); | |
}, i * 50); | |
} | |
// 启动特殊武器冷却计时器 | |
setTimeout(() => { | |
gameState.specialWeaponReady = true; | |
}, gameState.specialWeaponCooldown); | |
} | |
// 敌人发射子弹 | |
function enemyFireBullet(enemy) { | |
const now = Date.now(); | |
if (now - enemy.userData.lastShot < enemy.userData.shotDelay) return; | |
enemy.userData.lastShot = now; | |
// 从敌人位置发射子弹 | |
const bullet = createBullet( | |
enemy.position.x, | |
enemy.position.y, | |
enemy.position.z - 1, | |
true | |
); | |
// 设置子弹方向(朝向玩家) | |
const direction = new THREE.Vector3( | |
playerGroup.position.x - enemy.position.x, | |
playerGroup.position.y - enemy.position.y, | |
playerGroup.position.z - enemy.position.z | |
).normalize(); | |
bullet.userData.direction = direction; | |
// Boss发射更多的子弹 | |
if (enemy.userData.isBoss) { | |
// 创建额外的子弹,形成扇形攻击 | |
for (let i = 0; i < 3; i++) { | |
setTimeout(() => { | |
const angle = (i - 1) * 0.2; | |
const bullet = createBullet( | |
enemy.position.x, | |
enemy.position.y, | |
enemy.position.z - 1, | |
true | |
); | |
const dir = direction.clone(); | |
dir.x += angle; | |
bullet.userData.direction = dir.normalize(); | |
}, i * 100); | |
} | |
} | |
} | |
// 生成能量道具 | |
function spawnPowerUp() { | |
const now = Date.now(); | |
if (now - gameState.lastPowerUpSpawn < gameState.powerUpSpawnDelay) return; | |
gameState.lastPowerUpSpawn = now; | |
// 随机生成道具位置 | |
const x = (Math.random() - 0.5) * 30; | |
const y = (Math.random() - 0.5) * 10; | |
const z = 30 + Math.random() * 40; | |
createPowerUp(x, y, z); | |
} | |
// 更新UI | |
function updateUI() { | |
// 更新分数 | |
document.getElementById('score').textContent = `分数: ${gameState.score}`; | |
// 更新关卡 | |
document.getElementById('level').textContent = `关卡: ${gameState.level}`; | |
// 更新生命值 | |
const healthPercent = (gameState.health / gameState.maxHealth) * 100; | |
document.getElementById('health-fill').style.width = `${healthPercent}%`; | |
// 更新弹药 | |
document.getElementById('ammo').textContent = `弹药: ${gameState.ammo === Infinity ? '∞' : gameState.ammo}`; | |
// 更新敌人数量 | |
const enemiesLeft = gameState.enemiesSpawned - gameState.enemiesDestroyed; | |
document.getElementById('enemy-count').textContent = `敌人: ${enemiesLeft}`; | |
// 更新特殊武器状态 | |
const specialWeaponElement = document.getElementById('special-weapon'); | |
if (specialWeaponElement) { | |
specialWeaponElement.style.opacity = gameState.specialWeaponReady ? '1' : '0.5'; | |
} | |
// 更新Boss血条 | |
if (gameState.bossActive && gameState.boss) { | |
updateBossHealth(); | |
} | |
} | |
// 更新Boss血条 | |
function updateBossHealth() { | |
if (!gameState.boss || !gameState.bossActive) return; | |
const boss = gameState.boss.children[0]; | |
const healthPercent = (boss.userData.health / boss.userData.maxHealth) * 100; | |
document.getElementById('boss-health-fill').style.width = `${healthPercent}%`; | |
} | |
// 显示游戏结束 | |
function showGameOver() { | |
document.getElementById('final-score').textContent = gameState.score; | |
document.getElementById('final-level').textContent = gameState.level; | |
document.getElementById('game-over').style.display = 'flex'; | |
gameState.gameOver = true; | |
} | |
// 显示关卡完成 | |
function showLevelComplete() { | |
document.getElementById('level-score').textContent = gameState.score; | |
document.getElementById('next-level').textContent = gameState.level + 1; | |
document.getElementById('level-complete').style.display = 'flex'; | |
gameState.levelComplete = true; | |
} | |
// 应用能量道具效果 | |
function applyPowerUp(type) { | |
// 如果已经有相同类型的道具,先清除之前的 | |
if (gameState.activePowerUps[type]) { | |
clearTimeout(gameState.activePowerUps[type].timer); | |
} | |
// 应用道具效果 | |
switch (type) { | |
case 'health': | |
gameState.health = Math.min(gameState.health + 30, gameState.maxHealth); | |
updateUI(); | |
break; | |
case 'shield': | |
// 护盾效果在碰撞检测中处理 | |
break; | |
case 'speed': | |
// 速度效果在玩家移动中处理 | |
break; | |
case 'fireRate': | |
// 射击速度效果在射击函数中处理 | |
break; | |
case 'special': | |
gameState.specialWeaponReady = true; | |
break; | |
} | |
// 添加道具图标到UI | |
addPowerUpIcon(type); | |
// 设置道具持续时间 | |
gameState.activePowerUps[type] = { | |
active: true, | |
timer: setTimeout(() => { | |
removePowerUp(type); | |
}, GAME.POWERUP_DURATION) | |
}; | |
} | |
// 添加道具图标到UI | |
function addPowerUpIcon(type) { | |
const powerUpsContainer = document.getElementById('power-ups'); | |
// 如果已经有相同类型的图标,先移除 | |
const existingIcon = document.getElementById(`power-up-${type}`); | |
if (existingIcon) { | |
powerUpsContainer.removeChild(existingIcon); | |
} | |
const icon = document.createElement('div'); | |
icon.id = `power-up-${type}`; | |
icon.className = 'power-up-icon'; | |
// 根据类型设置图标 | |
switch (type) { | |
case 'health': | |
icon.innerHTML = '❤️'; | |
icon.style.backgroundColor = 'rgba(0, 255, 0, 0.3)'; | |
break; | |
case 'shield': | |
icon.innerHTML = '🛡️'; | |
icon.style.backgroundColor = 'rgba(0, 0, 255, 0.3)'; | |
break; | |
case 'speed': | |
icon.innerHTML = '⚡'; | |
icon.style.backgroundColor = 'rgba(255, 165, 0, 0.3)'; | |
break; | |
case 'fireRate': | |
icon.innerHTML = '🔥'; | |
icon.style.backgroundColor = 'rgba(255, 0, 255, 0.3)'; | |
break; | |
case 'special': | |
icon.innerHTML = '💣'; | |
icon.style.backgroundColor = 'rgba(255, 0, 0, 0.3)'; | |
break; | |
} | |
powerUpsContainer.appendChild(icon); | |
// 添加动画效果 | |
icon.style.transform = 'scale(0)'; | |
setTimeout(() => { | |
icon.style.transform = 'scale(1)'; | |
icon.style.transition = 'transform 0.3s'; | |
}, 10); | |
} | |
// 移除能量道具效果 | |
function removePowerUp(type) { | |
if (!gameState.activePowerUps[type]) return; | |
gameState.activePowerUps[type].active = false; | |
delete gameState.activePowerUps[type]; | |
// 从UI中移除图标 | |
const icon = document.getElementById(`power-up-${type}`); | |
if (icon) { | |
icon.style.transform = 'scale(0)'; | |
setTimeout(() => { | |
if (icon.parentNode) { | |
icon.parentNode.removeChild(icon); | |
} | |
}, 300); | |
} | |
} | |
// 更新雷达 | |
function updateRadar() { | |
// 清除旧的雷达标记 | |
radarBlips.forEach(blip => { | |
if (blip.parentNode) { | |
blip.parentNode.removeChild(blip); | |
} | |
}); | |
radarBlips = []; | |
// 添加玩家标记 | |
const playerBlip = document.createElement('div'); | |
playerBlip.className = 'radar-blip'; | |
playerBlip.style.backgroundColor = '#00ffff'; | |
playerBlip.style.left = '50%'; | |
playerBlip.style.top = '50%'; | |
document.getElementById('radar').appendChild(playerBlip); | |
radarBlips.push(playerBlip); | |
// 添加敌人标记 | |
gameState.enemies.forEach(enemy => { | |
// 计算敌人相对于玩家的位置 | |
const relativeX = enemy.position.x - playerGroup.position.x; | |
const relativeZ = enemy.position.z - playerGroup.position.z; | |
// 限制在雷达范围内 | |
const maxDistance = 50; | |
const distance = Math.min(Math.sqrt(relativeX * relativeX + relativeZ * relativeZ), maxDistance); | |
const angle = Math.atan2(relativeX, relativeZ); | |
// 转换为雷达坐标 | |
const radarX = 50 + (distance / maxDistance) * 50 * Math.sin(angle); | |
const radarY = 50 - (distance / maxDistance) * 50 * Math.cos(angle); | |
// 创建雷达标记 | |
const blip = document.createElement('div'); | |
blip.className = 'radar-blip'; | |
blip.style.left = `${radarX}%`; | |
blip.style.top = `${radarY}%`; | |
// Boss标记更大 | |
if (enemy.userData.isBoss) { | |
blip.style.width = '10px'; | |
blip.style.height = '10px'; | |
} | |
document.getElementById('radar').appendChild(blip); | |
radarBlips.push(blip); | |
}); | |
} | |
// 游戏主循环 | |
function animate() { | |
requestAnimationFrame(animate); | |
const delta = clock.getDelta(); | |
const time = clock.getElapsedTime(); | |
// 如果游戏结束或关卡完成,不更新游戏状态 | |
if (gameState.gameOver || gameState.levelComplete) { | |
effect.render(scene, camera); | |
return; | |
} | |
// 玩家移动 | |
const speedPower = gameState.activePowerUps['speed']; | |
const actualPlayerSpeed = speedPower ? GAME.PLAYER_SPEED * 1.5 : GAME.PLAYER_SPEED; | |
if (keys['KeyW']) playerGroup.position.z += actualPlayerSpeed; | |
if (keys['KeyS']) playerGroup.position.z -= actualPlayerSpeed; | |
if (keys['KeyA']) playerGroup.position.x -= actualPlayerSpeed; | |
if (keys['KeyD']) playerGroup.position.x += actualPlayerSpeed; | |
if (keys['Space']) playerGroup.position.y += actualPlayerSpeed; | |
if (keys['ShiftLeft']) playerGroup.position.y -= actualPlayerSpeed; | |
// 限制玩家移动范围 | |
playerGroup.position.x = Math.max(-15, Math.min(15, playerGroup.position.x)); | |
playerGroup.position.y = Math.max(-5, Math.min(5, playerGroup.position.y)); | |
playerGroup.position.z = Math.max(-15, Math.min(40, playerGroup.position.z)); | |
// 鼠标射击 | |
if (isMouseDown) { | |
fireBullet(); | |
} | |
// 生成能量道具 | |
spawnPowerUp(); | |
// 更新子弹 | |
updateBullets(delta); | |
// 更新敌人 | |
updateEnemies(delta, time); | |
// 更新能量道具 | |
updatePowerUps(delta); | |
// 检测碰撞 | |
checkCollisions(); | |
// 更新雷达 | |
updateRadar(); | |
// 更新UI | |
updateUI(); | |
// 渲染场景 | |
effect.render(scene, camera); | |
} | |
// 更新子弹 | |
function updateBullets(delta) { | |
// 玩家子弹 | |
for (let i = gameState.bullets.length - 1; i >= 0; i--) { | |
const bullet = gameState.bullets[i]; | |
// 移动子弹 | |
bullet.position.x += bullet.userData.direction.x * bullet.userData.speed * 60 * delta; | |
bullet.position.y += bullet.userData.direction.y * bullet.userData.speed * 60 * delta; | |
bullet.position.z += bullet.userData.direction.z * bullet.userData.speed * 60 * delta; | |
// 移除超出范围的子弹 | |
if (bullet.position.z > 100 || | |
bullet.position.z < -50 || | |
bullet.position.x < -50 || | |
bullet.position.x > 50 || | |
bullet.position.y < -20 || | |
bullet.position.y > 20) { | |
scene.remove(bullet); | |
gameState.bullets.splice(i, 1); | |
} | |
} | |
// 敌人子弹 | |
for (let i = gameState.enemyBullets.length - 1; i >= 0; i--) { | |
const bullet = gameState.enemyBullets[i]; | |
// 移动子弹 | |
bullet.position.x += bullet.userData.direction.x * bullet.userData.speed * 60 * delta; | |
bullet.position.y += bullet.userData.direction.y * bullet.userData.speed * 60 * delta; | |
bullet.position.z += bullet.userData.direction.z * bullet.userData.speed * 60 * delta; | |
// 移除超出范围的子弹 | |
if (bullet.position.z > 100 || | |
bullet.position.z < -50 || | |
bullet.position.x < -50 || | |
bullet.position.x > 50 || | |
bullet.position.y < -20 || | |
bullet.position.y > 20) { | |
scene.remove(bullet); | |
gameState.enemyBullets.splice(i, 1); | |
} | |
} | |
} | |
// 更新敌人 | |
function updateEnemies(delta, time) { | |
const currentLevel = Math.min(gameState.level - 1, GAME.LEVELS.length - 1); | |
const levelData = GAME.LEVELS[currentLevel]; | |
for (let i = gameState.enemies.length - 1; i >= 0; i--) { | |
const enemy = gameState.enemies[i]; | |
// Boss行为 | |
if (enemy.userData.isBoss) { | |
// Boss移动模式 | |
const bossMovePattern = time * 0.5; | |
enemy.position.x = Math.sin(bossMovePattern) * 10; | |
enemy.position.y = Math.cos(bossMovePattern * 0.7) * 3; | |
// Boss射击 | |
if (time - enemy.userData.lastShot > enemy.userData.shotDelay) { | |
enemyFireBullet(enemy); | |
} | |
} else { | |
// 普通敌人移动 | |
enemy.position.z -= enemy.userData.speed * 60 * delta; | |
// 敌人射击 | |
if (Math.random() < 0.01 && time - gameState.lastEnemyShot > levelData.spawnRate * 2) { | |
gameState.lastEnemyShot = time; | |
enemyFireBullet(enemy); | |
} | |
} | |
// 移除超出范围的敌人 | |
if (enemy.position.z < -30) { | |
scene.remove(enemy); | |
gameState.enemies.splice(i, 1); | |
// 如果敌人超出范围,减少生命值 | |
if (!enemy.userData.isBoss) { | |
gameState.health -= 5; | |
if (gameState.health <= 0) { | |
gameState.health = 0; | |
showGameOver(); | |
} | |
updateUI(); | |
} | |
} | |
} | |
// 检查关卡是否完成 | |
if (!gameState.bossActive && | |
gameState.enemiesSpawned >= levelData.enemies && | |
gameState.enemiesDestroyed >= levelData.enemies) { | |
// 如果是最后一关,游戏胜利 | |
if (gameState.level >= GAME.LEVELS.length) { | |
showGameOver(); // 这里可以改为显示胜利画面 | |
} else { | |
showLevelComplete(); | |
} | |
} | |
} | |
// 更新能量道具 | |
function updatePowerUps(delta) { | |
for (let i = gameState.powerUps.length - 1; i >= 0; i--) { | |
const powerUp = gameState.powerUps[i]; | |
// 旋转道具 | |
powerUp.rotation.x += 0.05 * 60 * delta; | |
powerUp.rotation.y += 0.05 * 60 * delta; | |
// 上下浮动 | |
powerUp.position.y += Math.sin(clock.getElapsedTime() * 3) * 0.01 * 60 * delta; | |
// 向玩家移动 | |
const direction = new THREE.Vector3( | |
playerGroup.position.x - powerUp.position.x, | |
playerGroup.position.y - powerUp.position.y, | |
playerGroup.position.z - powerUp.position.z | |
).normalize(); | |
powerUp.position.x += direction.x * powerUp.userData.speed * 60 * delta; | |
powerUp.position.y += direction.y * powerUp.userData.speed * 60 * delta; | |
powerUp.position.z += direction.z * powerUp.userData.speed * 60 * delta; | |
// 移除超出范围的子弹 | |
if (powerUp.position.z > 100 || | |
powerUp.position.z < -50 || | |
powerUp.position.x < -50 || | |
powerUp.position.x > 50 || | |
powerUp.position.y < -20 || | |
powerUp.position.y > 20) { | |
scene.remove(powerUp); | |
gameState.powerUps.splice(i, 1); | |
} | |
} | |
} | |
// 检测碰撞 | |
function checkCollisions() { | |
// 玩家子弹与敌人碰撞 | |
for (let i = gameState.bullets.length - 1; i >= 0; i--) { | |
const bullet = gameState.bullets[i]; | |
for (let j = gameState.enemies.length - 1; j >= 0; j--) { | |
const enemy = gameState.enemies[j]; | |
const enemyMesh = enemy.children[0]; | |
// 简单的距离检测碰撞 | |
const distance = bullet.position.distanceTo(enemyMesh.position); | |
if (distance < enemyMesh.geometry.boundingSphere.radius + 0.2) { | |
// 敌人受伤 | |
enemyMesh.userData.health--; | |
// 根据敌人血量改变颜色 | |
const healthPercent = enemyMesh.userData.health / enemyMesh.userData.maxHealth; | |
if (healthPercent < 0.33) { | |
enemyMesh.material.color.setHex(0xff0000); | |
enemyMesh.material.emissive.setHex(0x990000); | |
} else if (healthPercent < 0.66) { | |
enemyMesh.material.color.setHex(0xff9900); | |
enemyMesh.material.emissive.setHex(0x994400); | |
} | |
// 移除子弹 | |
scene.remove(bullet); | |
gameState.bullets.splice(i, 1); | |
// 如果敌人死亡 | |
if (enemyMesh.userData.health <= 0) { | |
// 增加分数 | |
const points = enemy.userData.isBoss ? 500 : 100 * gameState.level; | |
gameState.score += points; | |
// 随机掉落能量道具 | |
if (Math.random() < 0.3 || enemy.userData.isBoss) { | |
createPowerUp(enemy.position.x, enemy.position.y, enemy.position.z); | |
} | |
// 移除敌人 | |
scene.remove(enemy); | |
gameState.enemies.splice(j, 1); | |
gameState.enemiesDestroyed++; | |
// 如果是Boss | |
if (enemy.userData.isBoss) { | |
gameState.bossActive = false; | |
gameState.boss = null; | |
document.getElementById('boss-health').style.display = 'none'; | |
} | |
} | |
break; | |
} | |
} | |
} | |
// 敌人子弹与玩家碰撞 | |
for (let i = gameState.enemyBullets.length - 1; i >= 0; i--) { | |
const bullet = gameState.enemyBullets[i]; | |
// 简单的距离检测碰撞 | |
const distance = bullet.position.distanceTo(playerGroup.position); | |
if (distance < 1) { | |
// 如果有护盾,不受伤 | |
if (!gameState.activePowerUps['shield']) { | |
gameState.health -= 10; | |
if (gameState.health <= 0) { | |
gameState.health = 0; | |
showGameOver(); | |
} | |
} | |
// 移除子弹 | |
scene.remove(bullet); | |
gameState.enemyBullets.splice(i, 1); | |
} | |
} | |
// 能量道具与玩家碰撞 | |
for (let i = gameState.powerUps.length - 1; i >= 0; i--) { | |
const powerUp = gameState.powerUps[i]; | |
// 简单的距离检测碰撞 | |
const distance = powerUp.position.distanceTo(playerGroup.position); | |
if (distance < 1) { | |
// 应用道具效果 | |
applyPowerUp(powerUp.children[0].userData.type); | |
// 移除道具 | |
scene.remove(powerUp); | |
gameState.powerUps.splice(i, 1); | |
} | |
} | |
// 敌人与玩家碰撞 | |
for (let i = gameState.enemies.length - 1; i >= 0; i--) { | |
const enemy = gameState.enemies[i]; | |
const enemyMesh = enemy.children[0]; | |
// 简单的距离检测碰撞 | |
const distance = enemyMesh.position.distanceTo(playerGroup.position); | |
if (distance < enemyMesh.geometry.boundingSphere.radius + 0.5) { | |
// 如果有护盾,不受伤 | |
if (!gameState.activePowerUps['shield']) { | |
gameState.health -= 20; | |
if (gameState.health <= 0) { | |
gameState.health = 0; | |
showGameOver(); | |
} | |
} | |
// 敌人受伤 | |
enemyMesh.userData.health -= 5; | |
// 如果敌人死亡 | |
if (enemyMesh.userData.health <= 0) { | |
// 增加分数 | |
const points = enemy.userData.isBoss ? 500 : 100 * gameState.level; | |
gameState.score += points; | |
// 随机掉落能量道具 | |
if (Math.random() < 0.3 || enemy.userData.isBoss) { | |
createPowerUp(enemy.position.x, enemy.position.y, enemy.position.z); | |
} | |
// 移除敌人 | |
scene.remove(enemy); | |
gameState.enemies.splice(i, 1); | |
gameState.enemiesDestroyed++; | |
// 如果是Boss | |
if (enemy.userData.isBoss) { | |
gameState.bossActive = false; | |
gameState.boss = null; | |
document.getElementById('boss-health').style.display = 'none'; | |
} | |
} | |
break; | |
} | |
} | |
} | |
// 启动游戏 | |
init(); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=CYXiaofeng/fly-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |