fly-game / index.html
CYXiaofeng's picture
Add 2 files
42f63d4 verified
<!DOCTYPE html>
<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/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/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>