diff --git "a/index.html" "b/index.html"
--- "a/index.html"
+++ "b/index.html"
@@ -602,14 +602,22 @@
`;
}
- if (gameState.timeSlow > 0 && gameState.timeSlow < Date.now()) {
- gameState.timeSlow = 0;
- createEffect('时间恢复正常', 'cyan', 1500);
+ if (gameState.timeSlow > Date.now()) {
+ const timeLeft = Math.ceil((gameState.timeSlow - Date.now()) / 1000);
+ powerupStatus.innerHTML += `
+
+
+
+ `;
}
- if (gameState.doubleScore > 0 && gameState.doubleScore < Date.now()) {
- gameState.doubleScore = 0;
- createEffect('双倍分数结束', 'pink', 1500);
+ if (gameState.doubleScore > Date.now()) {
+ const timeLeft = Math.ceil((gameState.doubleScore - Date.now()) / 1000);
+ powerupStatus.innerHTML += `
+
+
+
+ `;
}
// 更新Boss血条
@@ -745,10 +753,8 @@
// 创建敌人子弹
function createEnemyBullet(x, y) {
- const size = 6;
- const speed = 8;
-
- // 计算子弹方向(朝向玩家)
+ const size = 8;
+ const speed = 5 + gameState.speed / 50;
const angle = Math.atan2(
gameState.plane.y - y,
gameState.plane.x - x
@@ -759,7 +765,8 @@
y,
size,
speed,
- angle
+ angle,
+ damage: 1
});
playSound('enemyShootSound');
@@ -774,8 +781,7 @@
const speed = Math.random() * 2 + 2 + gameState.speed / 50;
const type = Math.random() > 0.5 ? 'rectangle' : 'circle';
const health = type === 'rectangle' ? (width > 80 ? 3 : 2) : 1;
- const canShoot = Math.random() > 0.7; // 30%概率敌人会射击
- const shootRate = Math.random() * 2000 + 1000; // 射击间隔1-3秒
+ const canShoot = Math.random() > 0.7; // 30%的敌人会射击
// 碰撞体积比实际显示大20%
const collisionWidth = width * 1.2;
@@ -794,8 +800,8 @@
maxHealth: health,
isLarge: width > 80,
canShoot,
- shootRate,
- lastShootTime: 0
+ lastShootTime: 0,
+ shootCooldown: Math.random() * 2000 + 1000 // 射击冷却时间1-3秒
});
}
@@ -827,8 +833,8 @@
isLarge: true,
isBoss: true,
canShoot: true,
- shootRate: 500, // Boss射击更快
- lastShootTime: 0
+ lastShootTime: 0,
+ shootCooldown: 500 // Boss射击冷却时间0.5秒
});
createEffect('BOSS出现!', 'red', 2000);
@@ -903,1379 +909,1354 @@
rotationSpeed: (Math.random() - 0.5) * 0.2,
opacity: 1
});
- }
- }
+ }
+ }
- // 创建子弹
- function createBullet() {
- // 检查弹药是否足够
- if (gameState.ammo <= 0) {
- // 播放弹药不足音效
- if (!gameState.playedEmptySound) {
- playSound('emptySound');
- gameState.playedEmptySound = true;
- setTimeout(() => {
- gameState.playedEmptySound = false;
- }, 500);
- }
- return false; // 没有弹药了
- }
+ // 创建子弹
+ function createBullet() {
+ if (gameState.ammo <= 0) return false; // 没有弹药了
- // 根据火力增强状态调整子弹属性
- const isRapidFire = gameState.plane.powerups.rapidFire > Date.now();
- const bulletSize = isRapidFire ? 10 : 8;
- const bulletDamage = isRapidFire ? 2 : 1;
- const bulletSpeed = isRapidFire ? 18 : 15;
-
- // 计算子弹起始位置(从飞机前端发射)
- const bulletX = gameState.plane.x + 30;
- const bulletY = gameState.plane.y;
-
- // 创建子弹对象
- const newBullet = {
- x: bulletX,
- y: bulletY,
- size: bulletSize,
- speed: bulletSpeed,
- damage: bulletDamage,
- // 添加子弹轨迹点用于绘制尾迹
- trail: []
- };
-
- // 添加子弹到数组
- gameState.bullets.push(newBullet);
-
- // 如果有跟踪导弹能力且冷却结束,有70%概率发射跟踪导弹
- if (gameState.plane.powerups.homingMissiles > Date.now() && Math.random() > 0.3) {
- setTimeout(() => {
- createHomingMissile();
- }, 100); // 稍微延迟发射导弹,看起来更自然
- }
-
- // 如果弹药不是无限的,减少弹药
- if (gameState.ammo !== Infinity) {
- gameState.ammo--;
- }
-
- // 播放射击音效(火力增强时音效更高频)
- shootSound.playbackRate = isRapidFire ? 1.5 : 1.0;
- playSound('shootSound');
-
- // 更新UI
- updateUI();
-
- // 添加射击反冲效果
- gameState.plane.x -= 2 * Math.cos(gameState.plane.rotation * Math.PI / 180);
- gameState.plane.y -= 2 * Math.sin(gameState.plane.rotation * Math.PI / 180);
-
- // 添加枪口闪光效果
- createParticles(
- bulletX,
- bulletY,
- 5,
- isRapidFire ? '#ff9900' : '#ff6600'
- );
-
- return true;
+ const size = gameState.plane.powerups.rapidFire > Date.now() ? 10 : 8; // 火力增强时子弹更大
+ const damage = gameState.plane.powerups.rapidFire > Date.now() ? 2 : 1; // 火力增强时伤害更高
+ const speed = gameState.plane.powerups.rapidFire > Date.now() ? 18 : 15; // 火力增强时速度更快
+ const x = gameState.plane.x + 30; // 从飞机前端发射
+ const y = gameState.plane.y;
+
+ gameState.bullets.push({
+ x,
+ y,
+ size,
+ speed,
+ damage
+ });
+
+ // 如果有跟踪导弹能力且冷却结束
+ if (gameState.plane.powerups.homingMissiles > Date.now() &&
+ Math.random() > 0.7) { // 70%概率发射跟踪导弹
+ requestAnimationFrame(createHomingMissile);
}
-
- // 创建爆炸效果
- function createExplosion(x, y) {
- gameState.explosions.push({
- x,
- y,
- size: 0,
- maxSize: Math.random() * 40 + 40,
- alpha: 1
- });
- createParticles(x, y, 20, '#ff6600');
- playSound('explosionSound');
+
+ // 如果弹药不是无限的,减少弹药
+ if (gameState.ammo !== Infinity) {
+ gameState.ammo--;
}
+
+ playSound('shootSound');
+ updateUI();
+
+ return true;
+ }
- // 检测碰撞
- function checkCollision(rect1, rect2) {
- return (
- rect1.x < rect2.x + rect2.width &&
- rect1.x + rect1.width > rect2.x &&
- rect1.y < rect2.y + rect2.height &&
- rect1.y + rect1.height > rect2.y
- );
- }
+ // 创建爆炸效果
+ function createExplosion(x, y) {
+ gameState.explosions.push({
+ x,
+ y,
+ size: 0,
+ maxSize: Math.random() * 40 + 40,
+ alpha: 1
+ });
+ createParticles(x, y, 20, '#ff6600');
+ playSound('explosionSound');
+ }
- // 游戏结束
- function endGame() {
- gameState.gameOver = true;
- gameUI.classList.add('hidden');
- gameOverScreen.classList.remove('hidden');
- finalScore.textContent = gameState.score;
-
- // 更新最高分
- if (gameState.score > gameState.highScore) {
- gameState.highScore = gameState.score;
- localStorage.setItem('highScore', gameState.highScore);
- achievementsDisplay.innerHTML += `🎉 新纪录!
`;
- }
-
- // 显示成就
- if (!gameState.achievements.firstBlood) {
- achievementsDisplay.innerHTML += `🏆 首次击杀!
`;
- }
- if (!gameState.achievements.combo5) {
- achievementsDisplay.innerHTML += `🔥 连续5次击杀!
`;
- }
- if (!gameState.achievements.noDamage && gameState.lives === 3) {
- achievementsDisplay.innerHTML += `🛡️ 无伤通关!
`;
- }
- if (!gameState.achievements.bossSlayer && gameState.bossActive) {
- achievementsDisplay.innerHTML += `👹 Boss杀手!
`;
- }
-
- // 隐藏触摸控制按钮
- leftBtn.classList.add('hidden');
- rightBtn.classList.add('hidden');
- upBtn.classList.add('hidden');
- downBtn.classList.add('hidden');
- fireBtn.classList.add('hidden');
- joystick.classList.add('hidden');
-
- bgMusic.pause();
- }
+ // 检测碰撞
+function checkCollision(rect1, rect2) {
+ return (
+ rect1.x < rect2.x + rect2.width &&
+ rect1.x + rect1.width > rect2.x &&
+ rect1.y < rect2.y + rect2.height &&
+ rect1.y + rect1.height > rect2.y
+ );
+}
- // 游戏主循环
- function gameLoop(timestamp) {
- if (!gameState.started || gameState.gameOver) return;
-
- // 清除画布
- ctx.clearRect(0, 0, canvas.width, canvas.height);
-
- // 更新游戏状态
- updateGame(timestamp);
-
- // 绘制游戏元素
- drawGame();
-
- // 继续循环
- requestAnimationFrame(gameLoop);
- }
+// 游戏结束
+function endGame() {
+ gameState.gameOver = true;
+ gameUI.classList.add('hidden');
+ gameOverScreen.classList.remove('hidden');
+ finalScore.textContent = gameState.score;
+
+ // 更新最高分
+ if (gameState.score > gameState.highScore) {
+ gameState.highScore = gameState.score;
+ localStorage.setItem('highScore', gameState.highScore);
+ achievementsDisplay.innerHTML += `🎉 新纪录!
`;
+ }
+
+ // 显示成就
+ if (!gameState.achievements.firstBlood) {
+ achievementsDisplay.innerHTML += `🏆 首次击杀!
`;
+ }
+ if (!gameState.achievements.combo5) {
+ achievementsDisplay.innerHTML += `🔥 连续5次击杀!
`;
+ }
+ if (!gameState.achievements.noDamage && gameState.lives === 3) {
+ achievementsDisplay.innerHTML += `🛡️ 无伤通关!
`;
+ }
+ if (!gameState.achievements.bossSlayer && gameState.bossActive) {
+ achievementsDisplay.innerHTML += `👹 Boss杀手!
`;
+ }
+
+ // 隐藏触摸控制按钮
+ leftBtn.classList.add('hidden');
+ rightBtn.classList.add('hidden');
+ upBtn.classList.add('hidden');
+ downBtn.classList.add('hidden');
+ fireBtn.classList.add('hidden');
+ joystick.classList.add('hidden');
+
+ bgMusic.pause();
+}
- // 更新游戏状态
- function updateGame(timestamp) {
- // 随着分数增加难度
- gameState.difficulty = 1 + Math.min(gameState.score / 1000, 3);
-
- // 检查Boss生成条件
- if (!gameState.bossActive &&
- gameState.score > 0 &&
- gameState.score % 5000 === 0 &&
- timestamp - gameState.lastBossSpawnTime > 30000) { // 每5000分且30秒内未生成Boss
- createBoss();
- }
-
- // 时间减速因子
- const timeSlowFactor = gameState.timeSlow > Date.now() ? 0.5 : 1;
-
- // 处理开火
- if ((gameState.keys.Space || gameState.isFiring) &&
- timestamp - gameState.plane.lastFireTime > gameState.plane.fireRate) { // 射击冷却
- createBullet();
- gameState.plane.lastFireTime = timestamp;
- }
-
- // 检查道具是否过期
- if (gameState.plane.powerups.rapidFire > 0 && gameState.plane.powerups.rapidFire < Date.now()) {
- gameState.plane.powerups.rapidFire = 0;
- gameState.plane.fireRate = 200; // 恢复默认射击速度
- createEffect('火力增强结束', 'red', 1500);
- }
-
- if (gameState.plane.powerups.homingMissiles > 0 && gameState.plane.powerups.homingMissiles < Date.now()) {
- gameState.plane.powerups.homingMissiles = 0;
- createEffect('跟踪导弹结束', 'purple', 1500);
- }
-
- if (gameState.plane.hasShield && gameState.plane.shieldDuration < Date.now()) {
- gameState.plane.hasShield = false;
- createEffect('保护罩消失', 'blue', 1500);
- }
-
- if (gameState.timeSlow > 0 && gameState.timeSlow < Date.now()) {
- gameState.timeSlow = 0;
- createEffect('时间恢复正常', 'cyan', 1500);
- }
-
- if (gameState.doubleScore > 0 && gameState.doubleScore < Date.now()) {
- gameState.doubleScore = 0;
- createEffect('双倍分数结束', 'pink', 1500);
- }
-
- // 更新飞机速度
- if (gameState.keys.ArrowUp || gameState.keys.ArrowDown) {
- gameState.speed = Math.max(50,
- Math.min(200,
- gameState.speed + (gameState.keys.ArrowUp ? 0.5 : -0.5)
- )
- );
- }
-
- // 更新水平方向移动
- if (gameState.keys.ArrowLeft || gameState.joystickAngle < -Math.PI/4) {
- gameState.plane.rotation = Math.max(gameState.plane.rotation - 2, -20);
- gameState.plane.velocity = Math.max(gameState.plane.velocity - 0.5, -5);
- } else if (gameState.keys.ArrowRight || gameState.joystickAngle > Math.PI/4) {
- gameState.plane.rotation = Math.min(gameState.plane.rotation + 2, 20);
- gameState.plane.velocity = Math.min(gameState.plane.velocity + 0.5, 5);
- } else {
- // 如果没有按左右键,飞机逐渐回正
- gameState.plane.rotation *= 0.95;
- gameState.plane.velocity *= 0.95;
- if (Math.abs(gameState.plane.rotation) < 0.5) gameState.plane.rotation = 0;
- if (Math.abs(gameState.plane.velocity) < 0.5) gameState.plane.velocity = 0;
- }
-
- // 更新垂直方向移动
- if (gameState.keys.ArrowUp || (gameState.joystickActive && gameState.joystickAngle < -Math.PI/4 && gameState.joystickAngle > -3*Math.PI/4)) {
- gameState.plane.verticalVelocity = Math.max(gameState.plane.verticalVelocity - 0.5, -5);
- } else if (gameState.keys.ArrowDown || (gameState.joystickActive && gameState.joystickAngle > Math.PI/4 && gameState.joystickAngle < 3*Math.PI/4)) {
- gameState.plane.verticalVelocity = Math.min(gameState.plane.verticalVelocity + 0.5, 5);
- } else {
- // 如果没有按上下键,垂直速度逐渐归零
- gameState.plane.verticalVelocity *= 0.95;
- if (Math.abs(gameState.plane.verticalVelocity) < 0.5) gameState.plane.verticalVelocity = 0;
- }
-
- // 更新飞机位置
- gameState.plane.x += gameState.plane.velocity;
- gameState.plane.y += gameState.plane.verticalVelocity;
-
- // 限制飞机在屏幕内
- gameState.plane.x = Math.max(gameState.plane.width / 2, Math.min(gameState.plane.x, canvas.width - gameState.plane.width / 2));
- gameState.plane.y = Math.max(gameState.plane.height / 2, Math.min(gameState.plane.y, canvas.height - gameState.plane.height / 2));
-
- // 生成新星星
- if (timestamp - gameState.lastStarTime > 2000 / gameState.difficulty) {
- createStar();
- gameState.lastStarTime = timestamp;
- }
-
- // 生成新障碍物
- if (timestamp - gameState.lastObstacleTime > 1500 / gameState.difficulty * timeSlowFactor) {
- createObstacle();
- gameState.lastObstacleTime = timestamp;
- }
-
- // 生成新云朵
- if (timestamp - gameState.lastCloudTime > 1000 * timeSlowFactor) {
- createCloud();
- gameState.lastCloudTime = timestamp;
- }
-
- // 生成新道具 (每5-8秒)
- if (timestamp - gameState.lastPowerupTime > (Math.random() * 3000 + 5000) / gameState.difficulty * timeSlowFactor) {
- createPowerup();
- gameState.lastPowerupTime = timestamp;
+// 游戏主循环
+function gameLoop(timestamp) {
+ if (!gameState.started || gameState.gameOver) return;
+
+ // 清除画布
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // 更新游戏状态
+ updateGame(timestamp);
+
+ // 绘制游戏元素
+ drawGame();
+
+ // 继续循环
+ requestAnimationFrame(gameLoop);
+}
+
+// 更新游戏状态
+function updateGame(timestamp) {
+ // 随着分数增加难度
+ gameState.difficulty = 1 + Math.min(gameState.score / 1000, 3);
+
+ // 检查Boss生成条件
+ if (!gameState.bossActive &&
+ gameState.score > 0 &&
+ gameState.score % 5000 === 0 &&
+ timestamp - gameState.lastBossSpawnTime > 30000) { // 每5000分且30秒内未生成Boss
+ createBoss();
+ }
+
+ // 时间减速因子
+ const timeSlowFactor = gameState.timeSlow > Date.now() ? 0.5 : 1;
+
+ // 处理开火
+ if ((gameState.keys.Space || gameState.isFiring) &&
+ timestamp - gameState.plane.lastFireTime > gameState.plane.fireRate) { // 射击冷却
+ createBullet();
+ gameState.plane.lastFireTime = timestamp;
+ }
+
+ // 敌人射击
+ if (timestamp - gameState.lastEnemyShootTime > 1000 / gameState.difficulty) {
+ gameState.obstacles.forEach(obstacle => {
+ if (obstacle.canShoot && timestamp - obstacle.lastShootTime > obstacle.shootCooldown) {
+ createEnemyBullet(obstacle.x - obstacle.width/2, obstacle.y);
+ obstacle.lastShootTime = timestamp;
}
+ });
+ gameState.lastEnemyShootTime = timestamp;
+ }
+
+ // 更新敌人子弹
+ gameState.enemyBullets.forEach(bullet => {
+ bullet.x += Math.cos(bullet.angle) * bullet.speed * timeSlowFactor;
+ bullet.y += Math.sin(bullet.angle) * bullet.speed * timeSlowFactor;
+ });
+ gameState.enemyBullets = gameState.enemyBullets.filter(bullet =>
+ bullet.x > 0 && bullet.x < canvas.width &&
+ bullet.y > 0 && bullet.y < canvas.height
+ );
+
+ // 检查道具是否过期
+ if (gameState.plane.powerups.rapidFire > 0 && gameState.plane.powerups.rapidFire < Date.now()) {
+ gameState.plane.powerups.rapidFire = 0;
+ gameState.plane.fireRate = 200; // 恢复默认射击速度
+ createEffect('火力增强结束', 'red', 1500);
+ }
+
+ if (gameState.plane.powerups.homingMissiles > 0 && gameState.plane.powerups.homingMissiles < Date.now()) {
+ gameState.plane.powerups.homingMissiles = 0;
+ createEffect('跟踪导弹结束', 'purple', 1500);
+ }
+
+ if (gameState.plane.hasShield && gameState.plane.shieldDuration < Date.now()) {
+ gameState.plane.hasShield = false;
+ createEffect('保护罩消失', 'blue', 1500);
+ }
+
+ if (gameState.timeSlow > 0 && gameState.timeSlow < Date.now()) {
+ gameState.timeSlow = 0;
+ createEffect('时间恢复正常', 'cyan', 1500);
+ }
+
+ if (gameState.doubleScore > 0 && gameState.doubleScore < Date.now()) {
+ gameState.doubleScore = 0;
+ createEffect('双倍分数结束', 'pink', 1500);
+ }
+
+ // 更新飞机速度
+ if (gameState.keys.ArrowUp || gameState.keys.ArrowDown) {
+ gameState.speed = Math.max(50,
+ Math.min(200,
+ gameState.speed + (gameState.keys.ArrowUp ? 0.5 : -0.5)
+ )
+ );
+ }
+
+ // 更新水平方向移动
+ if (gameState.keys.ArrowLeft || gameState.joystickAngle < -Math.PI/4) {
+ gameState.plane.rotation = Math.max(gameState.plane.rotation - 2, -20);
+ gameState.plane.velocity = Math.max(gameState.plane.velocity - 0.5, -5);
+ } else if (gameState.keys.ArrowRight || gameState.joystickAngle > Math.PI/4) {
+ gameState.plane.rotation = Math.min(gameState.plane.rotation + 2, 20);
+ gameState.plane.velocity = Math.min(gameState.plane.velocity + 0.5, 5);
+ } else {
+ // 如果没有按左右键,飞机逐渐回正
+ gameState.plane.rotation *= 0.95;
+ gameState.plane.velocity *= 0.95;
+ if (Math.abs(gameState.plane.rotation) < 0.5) gameState.plane.rotation = 0;
+ if (Math.abs(gameState.plane.velocity) < 0.5) gameState.plane.velocity = 0;
+ }
+
+ // 更新垂直方向移动
+ if (gameState.keys.ArrowUp || (gameState.joystickActive && gameState.joystickAngle < -Math.PI/4 && gameState.joystickAngle > -3*Math.PI/4)) {
+ gameState.plane.verticalVelocity = Math.max(gameState.plane.verticalVelocity - 0.5, -5);
+ } else if (gameState.keys.ArrowDown || (gameState.joystickActive && gameState.joystickAngle > Math.PI/4 && gameState.joystickAngle < 3*Math.PI/4)) {
+ gameState.plane.verticalVelocity = Math.min(gameState.plane.verticalVelocity + 0.5, 5);
+ } else {
+ // 如果没有按上下键,垂直速度逐渐归零
+ gameState.plane.verticalVelocity *= 0.95;
+ if (Math.abs(gameState.plane.verticalVelocity) < 0.5) gameState.plane.verticalVelocity = 0;
+ }
+
+ // 更新飞机位置
+ gameState.plane.x += gameState.plane.velocity;
+ gameState.plane.y += gameState.plane.verticalVelocity;
+
+ // 限制飞机在屏幕内
+ gameState.plane.x = Math.max(gameState.plane.width / 2, Math.min(gameState.plane.x, canvas.width - gameState.plane.width / 2));
+ gameState.plane.y = Math.max(gameState.plane.height / 2, Math.min(gameState.plane.y, canvas.height - gameState.plane.height / 2));
+
+ // 生成新星星
+ if (timestamp - gameState.lastStarTime > 2000 / gameState.difficulty) {
+ createStar();
+ gameState.lastStarTime = timestamp;
+ }
+
+ // 生成新障碍物
+ if (timestamp - gameState.lastObstacleTime > 1500 / gameState.difficulty * timeSlowFactor) {
+ createObstacle();
+ gameState.lastObstacleTime = timestamp;
+ }
+
+ // 生成新云朵
+ if (timestamp - gameState.lastCloudTime > 1000 * timeSlowFactor) {
+ createCloud();
+ gameState.lastCloudTime = timestamp;
+ }
+
+ // 生成新道具 (每5-8秒)
+ if (timestamp - gameState.lastPowerupTime > (Math.random() * 3000 + 5000) / gameState.difficulty * timeSlowFactor) {
+ createPowerup();
+ gameState.lastPowerupTime = timestamp;
+ }
+
+ // 更新粒子
+ gameState.particles.forEach(particle => {
+ particle.x += particle.speedX;
+ particle.y += particle.speedY;
+ particle.life--;
+ });
+ gameState.particles = gameState.particles.filter(p => p.life > 0);
+
+ // 更新特效
+ gameState.effects = gameState.effects.filter(effect =>
+ Date.now() - effect.startTime < effect.duration
+ );
+
+ // 更新碎片
+ gameState.debris.forEach(debris => {
+ debris.x += debris.speedX;
+ debris.y += debris.speedY;
+ debris.rotation += debris.rotationSpeed;
+ debris.opacity -= 0.02;
+ });
+ gameState.debris = gameState.debris.filter(debris => debris.opacity > 0);
+
+ // 更新跟踪导弹
+ gameState.homingMissiles.forEach(missile => {
+ if (!missile.target || missile.target.hit) {
+ // 如果没有目标或目标已被击中,则直线飞行
+ missile.x += Math.cos(missile.angle) * missile.speed;
+ missile.y += Math.sin(missile.angle) * missile.speed;
+ } else {
+ // 计算新的角度以跟踪目标
+ const dx = missile.target.x - missile.x;
+ const dy = missile.target.y - missile.y;
+ const targetAngle = Math.atan2(dy, dx);
+
+ // 平滑转向
+ let angleDiff = targetAngle - missile.angle;
+ if (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
+ if (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
+
+ missile.angle += angleDiff * 0.1;
+ missile.x += Math.cos(missile.angle) * missile.speed;
+ missile.y += Math.sin(missile.angle) * missile.speed;
+
+ // 检测碰撞
+ const missileRect = {
+ x: missile.x - missile.size / 2,
+ y: missile.y - missile.size / 2,
+ width: missile.size,
+ height: missile.size
+ };
- // 敌人射击
- gameState.obstacles.forEach(obstacle => {
- if (obstacle.canShoot && timestamp - obstacle.lastShootTime > obstacle.shootRate) {
- createEnemyBullet(obstacle.x - obstacle.width/2, obstacle.y);
- obstacle.lastShootTime = timestamp;
- }
- });
-
- // 更新敌人子弹
- gameState.enemyBullets.forEach(bullet => {
- bullet.x -= bullet.speed * Math.cos(bullet.angle) * timeSlowFactor;
- bullet.y -= bullet.speed * Math.sin(bullet.angle) * timeSlowFactor;
- });
- gameState.enemyBullets = gameState.enemyBullets.filter(bullet =>
- bullet.x > 0 && bullet.x < canvas.width &&
- bullet.y > 0 && bullet.y < canvas.height
- );
-
- // 更新粒子
- gameState.particles.forEach(particle => {
- particle.x += particle.speedX;
- particle.y += particle.speedY;
- particle.life--;
- });
- gameState.particles = gameState.particles.filter(p => p.life > 0);
-
- // 更新特效
- gameState.effects = gameState.effects.filter(effect =>
- Date.now() - effect.startTime < effect.duration
- );
-
- // 更新碎片
- gameState.debris.forEach(debris => {
- debris.x += debris.speedX;
- debris.y += debris.speedY;
- debris.rotation += debris.rotationSpeed;
- debris.opacity -= 0.02;
- });
- gameState.debris = gameState.debris.filter(debris => debris.opacity > 0);
+ const targetRect = {
+ x: missile.target.x - missile.target.collisionWidth / 2,
+ y: missile.target.y - missile.target.collisionHeight / 2,
+ width: missile.target.collisionWidth,
+ height: missile.target.collisionHeight
+ };
- // 更新跟踪导弹
- gameState.homingMissiles.forEach(missile => {
- if (!missile.target || missile.target.hit) {
- // 如果没有目标或目标已被击中,则直线飞行
- missile.x += Math.cos(missile.angle) * missile.speed;
- missile.y += Math.sin(missile.angle) * missile.speed;
- } else {
- // 计算新的角度以跟踪目标
- const dx = missile.target.x - missile.x;
- const dy = missile.target.y - missile.y;
- const targetAngle = Math.atan2(dy, dx);
-
- // 平滑转向
- let angleDiff = targetAngle - missile.angle;
- if (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
- if (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
-
- missile.angle += angleDiff * 0.1;
- missile.x += Math.cos(missile.angle) * missile.speed;
- missile.y += Math.sin(missile.angle) * missile.speed;
-
- // 检测碰撞
- const missileRect = {
- x: missile.x - missile.size / 2,
- y: missile.y - missile.size / 2,
- width: missile.size,
- height: missile.size
- };
-
- const targetRect = {
- x: missile.target.x - missile.target.collisionWidth / 2,
- y: missile.target.y - missile.target.collisionHeight / 2,
- width: missile.target.collisionWidth,
- height: missile.target.collisionHeight
- };
+ if (checkCollision(missileRect, targetRect)) {
+ missile.hit = true;
+ missile.target.health -= 3; // 导弹伤害更高
+
+ if (missile.target.health <= 0) {
+ missile.target.hit = true;
+ const scoreBonus = missile.target.isBoss ? 500 : (missile.target.isLarge ? 30 : 15);
+ gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
+ updateUI();
- if (checkCollision(missileRect, targetRect)) {
- missile.hit = true;
- missile.target.health -= 3; // 导弹伤害更高
-
- if (missile.target.health <= 0) {
- missile.target.hit = true;
- const scoreBonus = missile.target.isBoss ? 500 : (missile.target.isLarge ? 30 : 15);
- gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
- updateUI();
-
- // 如果是大型障碍物但不是Boss,分裂成小型障碍物
- if (missile.target.isLarge && !missile.target.isBoss) {
- for (let i = 0; i < 3; i++) {
- gameState.obstacles.push({
- x: missile.target.x + (Math.random() - 0.5) * 50,
- y: missile.target.y + (Math.random() - 0.5) * 50,
- width: missile.target.width / 2,
- height: missile.target.height / 2,
- collisionWidth: missile.target.collisionWidth / 2,
- collisionHeight: missile.target.collisionHeight / 2,
- speed: missile.target.speed * 1.2,
- type: missile.target.type,
- health: 1,
- maxHealth: 1,
- isLarge: false
- });
- }
- }
-
- // 如果是Boss,标记Boss已击败
- if (missile.target.isBoss) {
- gameState.bossActive = false;
- gameState.achievements.bossSlayer = true;
- }
-
- // 创建碎片效果
- createDebris(missile.target, missile.target.isBoss ? 30 : 12);
+ // 如果是大型障碍物但不是Boss,分裂成小型障碍物
+ if (missile.target.isLarge && !missile.target.isBoss) {
+ for (let i = 0; i < 3; i++) {
+ gameState.obstacles.push({
+ x: missile.target.x + (Math.random() - 0.5) * 50,
+ y: missile.target.y + (Math.random() - 0.5) * 50,
+ width: missile.target.width / 2,
+ height: missile.target.height / 2,
+ collisionWidth: missile.target.collisionWidth / 2,
+ collisionHeight: missile.target.collisionHeight / 2,
+ speed: missile.target.speed * 1.2,
+ type: missile.target.type,
+ health: 1,
+ maxHealth: 1,
+ isLarge: false
+ });
}
-
- // 创建爆炸效果
- createExplosion(missile.x, missile.y);
}
+
+ // 如果是Boss,标记Boss已击败
+ if (missile.target.isBoss) {
+ gameState.bossActive = false;
+ gameState.achievements.bossSlayer = true;
+ }
+
+ // 创建碎片效果
+ createDebris(missile.target, missile.target.isBoss ? 30 : 12);
}
- });
- gameState.homingMissiles = gameState.homingMissiles.filter(missile =>
- missile.x < canvas.width && missile.x > 0 &&
- missile.y < canvas.height && missile.y > 0 &&
- !missile.hit
- );
-
- // 更新云朵
- gameState.clouds.forEach(cloud => {
- cloud.x -= cloud.speed * timeSlowFactor;
- });
- gameState.clouds = gameState.clouds.filter(cloud => cloud.x + cloud.size > 0);
-
- // 更新道具
- gameState.powerups.forEach(powerup => {
- powerup.x -= powerup.speed * timeSlowFactor;
- // 检测与飞机的碰撞
- const planeRect = {
- x: gameState.plane.x - gameState.plane.width / 2,
- y: gameState.plane.y - gameState.plane.height / 2,
- width: gameState.plane.width,
- height: gameState.plane.height
- };
-
- const powerupRect = {
- x: powerup.x - powerup.size / 2,
- y: powerup.y - powerup.size / 2,
- width: powerup.size,
- height: powerup.size
- };
+ // 创建爆炸效果
+ createExplosion(missile.x, missile.y);
+ }
+ }
+ });
+ gameState.homingMissiles = gameState.homingMissiles.filter(missile =>
+ missile.x < canvas.width && missile.x > 0 &&
+ missile.y < canvas.height && missile.y > 0 &&
+ !missile.hit
+ );
+
+ // 更新云朵
+ gameState.clouds.forEach(cloud => {
+ cloud.x -= cloud.speed * timeSlowFactor;
+ });
+ gameState.clouds = gameState.clouds.filter(cloud => cloud.x + cloud.size > 0);
+
+ // 更新道具
+ gameState.powerups.forEach(powerup => {
+ powerup.x -= powerup.speed * timeSlowFactor;
+
+ // 检测与飞机的碰撞
+ const planeRect = {
+ x: gameState.plane.x - gameState.plane.width / 2,
+ y: gameState.plane.y - gameState.plane.height / 2,
+ width: gameState.plane.width,
+ height: gameState.plane.height
+ };
+
+ const powerupRect = {
+ x: powerup.x - powerup.size / 2,
+ y: powerup.y - powerup.size / 2,
+ width: powerup.size,
+ height: powerup.size
+ };
+
+ if (checkCollision(planeRect, powerupRect) && !gameState.gameOver) {
+ powerup.collected = true;
+ powerup.type.effect(gameState);
+ updateUI();
+ createParticles(powerup.x, powerup.y, 15, powerup.type.color);
+ }
+ });
+ gameState.powerups = gameState.powerups.filter(powerup =>
+ powerup.x + powerup.size > 0 && !powerup.collected
+ );
+
+ // 更新子弹
+ gameState.bullets.forEach(bullet => {
+ bullet.x += bullet.speed * timeSlowFactor;
+ });
+ gameState.bullets = gameState.bullets.filter(bullet => bullet.x < canvas.width);
+
+ // 检查敌人子弹与飞机的碰撞
+ gameState.enemyBullets.forEach(bullet => {
+ const bulletRect = {
+ x: bullet.x - bullet.size / 2,
+ y: bullet.y - bullet.size / 2,
+ width: bullet.size,
+ height: bullet.size
+ };
+
+ const planeRect = {
+ x: gameState.plane.x - gameState.plane.width / 2,
+ y: gameState.plane.y - gameState.plane.height / 2,
+ width: gameState.plane.width,
+ height: gameState.plane.height
+ };
+
+ if (checkCollision(bulletRect, planeRect) {
+ bullet.hit = true;
+ if (!gameState.plane.hasShield || gameState.plane.shieldDuration < Date.now()) {
+ gameState.lives--;
+ updateUI();
+ createExplosion(gameState.plane.x, gameState.plane.y);
- if (checkCollision(planeRect, powerupRect) && !gameState.gameOver) {
- powerup.collected = true;
- powerup.type.effect(gameState);
- updateUI();
- createParticles(powerup.x, powerup.y, 15, powerup.type.color);
+ if (gameState.lives <= 0) {
+ endGame();
}
- });
- gameState.powerups = gameState.powerups.filter(powerup =>
- powerup.x + powerup.size > 0 && !powerup.collected
- );
-
- // 更新子弹
- gameState.bullets.forEach(bullet => {
- bullet.x += bullet.speed * timeSlowFactor;
- });
- gameState.bullets = gameState.bullets.filter(bullet => bullet.x < canvas.width);
-
- // 更新星星
- gameState.stars.forEach(star => {
- star.x -= star.speed * timeSlowFactor;
- star.rotation += star.rotationSpeed;
-
- // 检测碰撞
- const planeRect = {
- x: gameState.plane.x - gameState.plane.width / 2,
- y: gameState.plane.y - gameState.plane.height / 2,
- width: gameState.plane.width,
- height: gameState.plane.height
- };
-
- const starRect = {
- x: star.x - star.size / 2,
- y: star.y - star.size / 2,
- width: star.size,
- height: star.size
- };
+ } else {
+ // 保护罩被击中
+ createExplosion(bullet.x, bullet.y);
+ }
+ }
+ });
+ gameState.enemyBullets = gameState.enemyBullets.filter(bullet => !bullet.hit);
+
+ // 更新星星
+ gameState.stars.forEach(star => {
+ star.x -= star.speed * timeSlowFactor;
+ star.rotation += star.rotationSpeed;
+
+ // 检测碰撞
+ const planeRect = {
+ x: gameState.plane.x - gameState.plane.width / 2,
+ y: gameState.plane.y - gameState.plane.height / 2,
+ width: gameState.plane.width,
+ height: gameState.plane.height
+ };
+
+ const starRect = {
+ x: star.x - star.size / 2,
+ y: star.y - star.size / 2,
+ width: star.size,
+ height: star.size
+ };
+
+ if (checkCollision(planeRect, starRect) && !gameState.gameOver) {
+ star.collected = true;
+ const scoreBonus = 10;
+ gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
+ updateUI();
+ createParticles(star.x, star.y, 10, 'gold');
+ }
+ });
+ gameState.stars = gameState.stars.filter(star => star.x + star.size > 0 && !star.collected);
+
+ // 更新障碍物
+ let comboCount = 0; // 连续击杀计数器
+ gameState.obstacles.forEach(obstacle => {
+ obstacle.x -= obstacle.speed * timeSlowFactor;
+
+ // 检测与飞机的碰撞
+ const planeRect = {
+ x: gameState.plane.x - gameState.plane.width / 2,
+ y: gameState.plane.y - gameState.plane.height / 2,
+ width: gameState.plane.width,
+ height: gameState.plane.height
+ };
+
+ const obstacleRect = {
+ x: obstacle.x - obstacle.collisionWidth / 2,
+ y: obstacle.y - obstacle.collisionHeight / 2,
+ width: obstacle.collisionWidth,
+ height: obstacle.collisionHeight
+ };
+
+ if (checkCollision(planeRect, obstacleRect) && !gameState.gameOver) {
+ // 如果有保护罩则不会受伤
+ if (!gameState.plane.hasShield || gameState.plane.shieldDuration < Date.now()) {
+ obstacle.hit = true;
+ gameState.lives--;
+ updateUI();
+ createExplosion(gameState.plane.x, gameState.plane.y);
- if (checkCollision(planeRect, starRect) && !gameState.gameOver) {
- star.collected = true;
- const scoreBonus = 10;
- gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
- updateUI();
- createParticles(star.x, star.y, 10, 'gold');
+ if (gameState.lives <= 0) {
+ endGame();
}
- });
- gameState.stars = gameState.stars.filter(star => star.x + star.size > 0 && !star.collected);
+ } else {
+ // 保护罩被击中
+ obstacle.hit = true;
+ createExplosion(obstacle.x, obstacle.y);
+ createDebris(obstacle, 4);
+ }
+ }
+
+ // 检测与子弹的碰撞
+ if (!obstacle.hit) {
+ const bulletHits = [];
- // 更新障碍物
- let comboCount = 0; // 连续击杀计数器
- gameState.obstacles.forEach(obstacle => {
- obstacle.x -= obstacle.speed * timeSlowFactor;
-
- // 检测与飞机的碰撞
- const planeRect = {
- x: gameState.plane.x - gameState.plane.width / 2,
- y: gameState.plane.y - gameState.plane.height / 2,
- width: gameState.plane.width,
- height: gameState.plane.height
+ gameState.bullets.forEach((bullet, bulletIndex) => {
+ const bulletRect = {
+ x: bullet.x - bullet.size / 2,
+ y: bullet.y - bullet.size / 2,
+ width: bullet.size,
+ height: bullet.size
};
- const obstacleRect = {
+ const obstacleCollisionRect = {
x: obstacle.x - obstacle.collisionWidth / 2,
y: obstacle.y - obstacle.collisionHeight / 2,
width: obstacle.collisionWidth,
height: obstacle.collisionHeight
};
- if (checkCollision(planeRect, obstacleRect) && !gameState.gameOver) {
- // 如果有保护罩则不会受伤
- if (!gameState.plane.hasShield || gameState.plane.shieldDuration < Date.now()) {
+ if (checkCollision(bulletRect, obstacleCollisionRect)) {
+ obstacle.health -= bullet.damage;
+ bulletHits.push(bulletIndex);
+ createExplosion(bullet.x, bullet.y);
+
+ if (obstacle.health <= 0) {
obstacle.hit = true;
- gameState.lives--;
+ const scoreBonus = obstacle.isBoss ? 500 : (obstacle.isLarge ? 30 : 15);
+ gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
updateUI();
- createExplosion(gameState.plane.x, gameState.plane.y);
+ comboCount++;
- if (gameState.lives <= 0) {
- endGame();
+ // 如果是大型障碍物但不是Boss,分裂成小型障碍物
+ if (obstacle.isLarge && !obstacle.isBoss) {
+ for (let i = 0; i < 3; i++) {
+ gameState.obstacles.push({
+ x: obstacle.x + (Math.random() - 0.5) * 50,
+ y: obstacle.y + (Math.random() - 0.5) * 50,
+ width: obstacle.width / 2,
+ height: obstacle.height / 2,
+ collisionWidth: obstacle.collisionWidth / 2,
+ collisionHeight: obstacle.collisionHeight / 2,
+ speed: obstacle.speed * 1.2,
+ type: obstacle.type,
+ health: 1,
+ maxHealth: 1,
+ isLarge: false
+ });
+ }
}
- } else {
- // 保护罩被击中
- obstacle.hit = true;
- createExplosion(obstacle.x, obstacle.y);
- createDebris(obstacle, 4);
- }
- }
-
- // 检测与子弹的碰撞
- if (!obstacle.hit) {
- const bulletHits = [];
-
- gameState.bullets.forEach((bullet, bulletIndex) => {
- const bulletRect = {
- x: bullet.x - bullet.size / 2,
- y: bullet.y - bullet.size / 2,
- width: bullet.size,
- height: bullet.size
- };
-
- const obstacleCollisionRect = {
- x: obstacle.x - obstacle.collisionWidth / 2,
- y: obstacle.y - obstacle.collisionHeight / 2,
- width: obstacle.collisionWidth,
- height: obstacle.collisionHeight
- };
- if (checkCollision(bulletRect, obstacleCollisionRect)) {
- obstacle.health -= bullet.damage;
- bulletHits.push(bulletIndex);
- createExplosion(bullet.x, bullet.y);
-
- if (obstacle.health <= 0) {
- obstacle.hit = true;
- const scoreBonus = obstacle.isBoss ? 500 : (obstacle.isLarge ? 30 : 15);
- gameState.score += gameState.doubleScore > Date.now() ? scoreBonus * 2 : scoreBonus;
- updateUI();
- comboCount++;
-
- // 如果是大型障碍物但不是Boss,分裂成小型障碍物
- if (obstacle.isLarge && !obstacle.isBoss) {
- for (let i = 0; i < 3; i++) {
- gameState.obstacles.push({
- x: obstacle.x + (Math.random() - 0.5) * 50,
- y: obstacle.y + (Math.random() - 0.5) * 50,
- width: obstacle.width / 2,
- height: obstacle.height / 2,
- collisionWidth: obstacle.collisionWidth / 2,
- collisionHeight: obstacle.collisionHeight / 2,
- speed: obstacle.speed * 1.2,
- type: obstacle.type,
- health: 1,
- maxHealth: 1,
- isLarge: false
- });
- }
- }
-
- // 如果是Boss,标记Boss已击败
- if (obstacle.isBoss) {
- gameState.bossActive = false;
- gameState.achievements.bossSlayer = true;
- }
-
- // 创建碎片效果
- createDebris(obstacle, obstacle.isBoss ? 30 : 8);
-
- // 首次击杀成就
- if (!gameState.achievements.firstBlood) {
- gameState.achievements.firstBlood = true;
- createEffect('首次击杀!', 'green', 2000);
- }
- }
+ // 如果是Boss,标记Boss已击败
+ if (obstacle.isBoss) {
+ gameState.bossActive = false;
+ gameState.achievements.bossSlayer = true;
}
- });
-
- // 连续击杀成就
- if (comboCount >= 5 && !gameState.achievements.combo5) {
- gameState.achievements.combo5 = true;
- createEffect('连续5次击杀!', 'blue', 2000);
- }
-
- // 移除已经击中的子弹
- for (let i = bulletHits.length - 1; i >= 0; i--) {
- gameState.bullets.splice(bulletHits[i], 1);
- }
- }
- });
- gameState.obstacles = gameState.obstacles.filter(obstacle => obstacle.x + obstacle.width > 0 && !obstacle.hit);
-
- // 检测玩家与敌人子弹的碰撞
- gameState.enemyBullets.forEach((bullet, index) => {
- const bulletRect = {
- x: bullet.x - bullet.size / 2,
- y: bullet.y - bullet.size / 2,
- width: bullet.size,
- height: bullet.size
- };
-
- const planeRect = {
- x: gameState.plane.x - gameState.plane.width / 2,
- y: gameState.plane.y - gameState.plane.height / 2,
- width: gameState.plane.width,
- height: gameState.plane.height
- };
-
- if (checkCollision(bulletRect, planeRect) && !gameState.gameOver) {
- // 如果有保护罩则不会受伤
- if (!gameState.plane.hasShield || gameState.plane.shieldDuration < Date.now()) {
- gameState.enemyBullets.splice(index, 1);
- gameState.lives--;
- updateUI();
- createExplosion(bullet.x, bullet.y);
- if (gameState.lives <= 0) {
- endGame();
+ // 创建碎片效果
+ createDebris(obstacle, obstacle.isBoss ? 30 : 8);
+
+ // 首次击杀成就
+ if (!gameState.achievements.firstBlood) {
+ gameState.achievements.firstBlood = true;
+ createEffect('首次击杀!', 'green', 2000);
}
- } else {
- // 保护罩被击中
- gameState.enemyBullets.splice(index, 1);
- createExplosion(bullet.x, bullet.y);
}
}
});
- // 更新爆炸效果
- gameState.explosions.forEach(explosion => {
- explosion.size += 2;
- explosion.alpha -= 0.02;
- });
- gameState.explosions = gameState.explosions.filter(explosion => explosion.alpha > 0);
+ // 连续击杀成就
+ if (comboCount >= 5 && !gameState.achievements.combo5) {
+ gameState.achievements.combo5 = true;
+ createEffect('连续5次击杀!', 'blue', 2000);
+ }
+
+ // 移除已经击中的子弹
+ for (let i = bulletHits.length - 1; i >= 0; i--) {
+ gameState.bullets.splice(bulletHits[i], 1);
+ }
}
+ });
+ gameState.obstacles = gameState.obstacles.filter(obstacle => obstacle.x + obstacle.width > 0 && !obstacle.hit);
+
+ // 更新爆炸效果
+ gameState.explosions.forEach(explosion => {
+ explosion.size += 2;
+ explosion.alpha -= 0.02;
+ });
+ gameState.explosions = gameState.explosions.filter(explosion => explosion.alpha > 0);
+}
- // 绘制游戏元素
- function drawGame() {
- // 绘制背景渐变
- const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
- gradient.addColorStop(0, '#1e3c72');
- gradient.addColorStop(1, '#2a5298');
- ctx.fillStyle = gradient;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
-
- // 绘制云朵
- gameState.clouds.forEach(cloud => {
- cloud.parts.forEach(part => {
- ctx.beginPath();
- ctx.arc(
- cloud.x + part.offsetX,
- cloud.y + part.offsetY,
- part.size / 2,
- 0,
- Math.PI * 2
- );
- ctx.fillStyle = `rgba(255, 255, 255, ${0.7 + Math.random() * 0.3})`;
- ctx.fill();
- });
- });
-
- // 绘制粒子
- gameState.particles.forEach(particle => {
- ctx.beginPath();
- ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
- ctx.fillStyle = particle.color;
- ctx.globalAlpha = particle.life / 100;
- ctx.fill();
- ctx.globalAlpha = 1;
- });
+// 绘制游戏元素
+function drawGame() {
+ // 绘制背景渐变
+ const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
+ gradient.addColorStop(0, '#1e3c72');
+ gradient.addColorStop(1, '#2a5298');
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ // 绘制云朵
+ gameState.clouds.forEach(cloud => {
+ cloud.parts.forEach(part => {
+ ctx.beginPath();
+ ctx.arc(
+ cloud.x + part.offsetX,
+ cloud.y + part.offsetY,
+ part.size / 2,
+ 0,
+ Math.PI * 2
+ );
+ ctx.fillStyle = `rgba(255, 255, 255, ${0.7 + Math.random() * 0.3})`;
+ ctx.fill();
+ });
+ });
+
+ // 绘制粒子
+ gameState.particles.forEach(particle => {
+ ctx.beginPath();
+ ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
+ ctx.fillStyle = particle.color;
+ ctx.globalAlpha = particle.life / 100;
+ ctx.fill();
+ ctx.globalAlpha = 1;
+ });
+
+ // 绘制碎片
+ gameState.debris.forEach(debris => {
+ ctx.save();
+ ctx.translate(debris.x, debris.y);
+ ctx.rotate(debris.rotation);
+
+ ctx.fillStyle = `rgba(100, 100, 100, ${debris.opacity})`;
+ ctx.fillRect(
+ -debris.width / 2,
+ -debris.height / 2,
+ debris.width,
+ debris.height
+ );
+
+ ctx.restore();
+ });
+
+ // 绘制敌人子弹
+ gameState.enemyBullets.forEach(bullet => {
+ const gradient = ctx.createRadialGradient(
+ bullet.x, bullet.y, 0,
+ bullet.x, bullet.y, bullet.size
+ );
+ gradient.addColorStop(0, '#f00');
+ gradient.addColorStop(1, '#800');
+
+ ctx.beginPath();
+ ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
+ ctx.fillStyle = gradient;
+ ctx.fill();
+
+ // 子弹尾迹
+ ctx.beginPath();
+ ctx.moveTo(bullet.x - Math.cos(bullet.angle) * 10, bullet.y - Math.sin(bullet.angle) * 10);
+ ctx.lineTo(bullet.x, bullet.y);
+ ctx.strokeStyle = 'rgba(255, 100, 100, 0.8)';
+ ctx.lineWidth = bullet.size / 2;
+ ctx.stroke();
+ });
+
+ // 绘制道具
+ gameState.powerups.forEach(powerup => {
+ ctx.save();
+ ctx.translate(powerup.x, powerup.y);
+
+ // 绘制闪光效果
+ ctx.beginPath();
+ ctx.arc(0, 0, powerup.size / 2, 0, Math.PI * 2);
+ const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, powerup.size / 2);
+ gradient.addColorStop(0, powerup.type.color);
+ gradient.addColorStop(1, 'rgba(255,255,255,0)');
+ ctx.fillStyle = gradient;
+ ctx.globalAlpha = 0.3;
+ ctx.fill();
+ ctx.globalAlpha = 1;
+
+ // 绘制道具图标
+ ctx.fillStyle = powerup.type.color;
+ ctx.beginPath();
+ ctx.arc(0, 0, powerup.size / 2 - 3, 0, Math.PI * 2);
+ ctx.fill();
+
+ // 绘制边框
+ ctx.strokeStyle = 'white';
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ // 绘制道具图标
+ ctx.fillStyle = 'white';
+ ctx.font = '20px FontAwesome';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(String.fromCharCode(parseInt(getIconCode(powerup.type.icon), 16)), 0, 1);
+
+ ctx.restore();
+ });
+
+ // 绘制跟踪导弹
+ gameState.homingMissiles.forEach(missile => {
+ ctx.save();
+ ctx.translate(missile.x, missile.y);
+ ctx.rotate(missile.angle);
+
+ // 导弹主体
+ ctx.fillStyle = 'red';
+ ctx.beginPath();
+ ctx.moveTo(missile.size / 2, 0);
+ ctx.lineTo(-missile.size / 2, -missile.size / 3);
+ ctx.lineTo(-missile.size / 2, missile.size / 3);
+ ctx.closePath();
+ ctx.fill();
+
+ // 火焰效果
+ ctx.fillStyle = 'orange';
+ ctx.beginPath();
+ ctx.moveTo(-missile.size / 2, -missile.size / 4);
+ ctx.lineTo(-missile.size, 0);
+ ctx.lineTo(-missile.size / 2, missile.size / 4);
+ ctx.closePath();
+ ctx.fill();
+
+ ctx.restore();
+ });
+
+ // 绘制子弹
+ gameState.bullets.forEach(bullet => {
+ const gradient = ctx.createRadialGradient(
+ bullet.x, bullet.y, 0,
+ bullet.x, bullet.y, bullet.size
+ );
+ gradient.addColorStop(0, '#ff0');
+ gradient.addColorStop(1, '#f80');
+
+ ctx.beginPath();
+ ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
+ ctx.fillStyle = gradient;
+ ctx.fill();
+
+ // 子弹尾迹
+ ctx.beginPath();
+ ctx.moveTo(bullet.x - bullet.speed, bullet.y);
+ ctx.lineTo(bullet.x, bullet.y);
+ ctx.strokeStyle = 'rgba(255, 200, 0, 0.8)';
+ ctx.lineWidth = bullet.size / 2;
+ ctx.stroke();
+ });
+
+ // 绘制星星
+ gameState.stars.forEach(star => {
+ ctx.save();
+ ctx.translate(star.x, star.y);
+ ctx.rotate(star.rotation);
+
+ ctx.beginPath();
+ for (let i = 0; i < 5; i++) {
+ const angle = (i * 2 * Math.PI / 5) - Math.PI / 2;
+ const innerAngle = angle + Math.PI / 5;
+ const outerRadius = star.size / 2;
+ const innerRadius = star.size / 4;
+
+ if (i === 0) {
+ ctx.moveTo(
+ Math.cos(angle) * outerRadius,
+ Math.sin(angle) * outerRadius
+ );
+ } else {
+ ctx.lineTo(
+ Math.cos(angle) * outerRadius,
+ Math.sin(angle) * outerRadius
+ );
+ }
- // 绘制碎片
- gameState.debris.forEach(debris => {
- ctx.save();
- ctx.translate(debris.x, debris.y);
- ctx.rotate(debris.rotation);
-
- ctx.fillStyle = `rgba(100, 100, 100, ${debris.opacity})`;
+ ctx.lineTo(
+ Math.cos(innerAngle) * innerRadius,
+ Math.sin(innerAngle) * innerRadius
+ );
+ }
+ ctx.closePath();
+
+ const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, star.size / 2);
+ gradient.addColorStop(0, 'gold');
+ gradient.addColorStop(1, 'yellow');
+ ctx.fillStyle = gradient;
+ ctx.shadowColor = 'yellow';
+ ctx.shadowBlur = 10;
+ ctx.fill();
+
+ ctx.restore();
+ });
+
+ // 绘制障碍物
+ gameState.obstacles.forEach(obstacle => {
+ ctx.save();
+ ctx.translate(obstacle.x, obstacle.y);
+
+ if (obstacle.type === 'rectangle') {
+ // 绘制健康条 (如果是矩形障碍物)
+ if (obstacle.health < obstacle.maxHealth) {
+ const healthBarWidth = obstacle.isBoss ? 100 : 20;
+ ctx.fillStyle = 'red';
ctx.fillRect(
- -debris.width / 2,
- -debris.height / 2,
- debris.width,
- debris.height
+ -healthBarWidth / 2,
+ -obstacle.height / 2 - 15,
+ healthBarWidth,
+ 5
);
-
- ctx.restore();
- });
+ ctx.fillStyle = obstacle.isBoss ? 'purple' : 'lime';
+ ctx.fillRect(
+ -healthBarWidth / 2,
+ -obstacle.height / 2 - 15,
+ healthBarWidth * (obstacle.health / obstacle.maxHealth),
+ 5
+ );
+ }
- // 绘制道具
- gameState.powerups.forEach(powerup => {
- ctx.save();
- ctx.translate(powerup.x, powerup.y);
-
- // 绘制闪光效果
+ // 绘制敌人飞机
+ if (obstacle.canShoot) {
+ // 飞机主体
+ ctx.fillStyle = obstacle.isBoss ? '#8B0000' : '#333';
ctx.beginPath();
- ctx.arc(0, 0, powerup.size / 2, 0, Math.PI * 2);
- const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, powerup.size / 2);
- gradient.addColorStop(0, powerup.type.color);
- gradient.addColorStop(1, 'rgba(255,255,255,0)');
- ctx.fillStyle = gradient;
- ctx.globalAlpha = 0.3;
+ ctx.moveTo(-obstacle.width/2, 0);
+ ctx.lineTo(obstacle.width/2, -obstacle.height/3);
+ ctx.lineTo(obstacle.width/2, obstacle.height/3);
+ ctx.closePath();
ctx.fill();
- ctx.globalAlpha = 1;
- // 绘制道具图标
- ctx.fillStyle = powerup.type.color;
+ // 机翼
+ ctx.fillStyle = obstacle.isBoss ? '#600000' : '#222';
ctx.beginPath();
- ctx.arc(0, 0, powerup.size / 2 - 3, 0, Math.PI * 2);
+ ctx.moveTo(-obstacle.width/4, 0);
+ ctx.lineTo(obstacle.width/4, -obstacle.height/2);
+ ctx.lineTo(obstacle.width/2, -obstacle.height/3);
+ ctx.lineTo(obstacle.width/4, 0);
+ ctx.closePath();
ctx.fill();
- // 绘制边框
- ctx.strokeStyle = 'white';
- ctx.lineWidth = 2;
- ctx.stroke();
-
- // 绘制道具图标
- ctx.fillStyle = 'white';
- ctx.font = '20px FontAwesome';
- ctx.textAlign = 'center';
- ctx.textBaseline = 'middle';
- ctx.fillText(String.fromCharCode(parseInt(getIconCode(powerup.type.icon), 16)), 0, 1);
-
- ctx.restore();
- });
-
- // 绘制跟踪导弹
- gameState.homingMissiles.forEach(missile => {
- ctx.save();
- ctx.translate(missile.x, missile.y);
- ctx.rotate(missile.angle);
-
- // 导弹主体
- ctx.fillStyle = 'red';
ctx.beginPath();
- ctx.moveTo(missile.size / 2, 0);
- ctx.lineTo(-missile.size / 2, -missile.size / 3);
- ctx.lineTo(-missile.size / 2, missile.size / 3);
+ ctx.moveTo(-obstacle.width/4, 0);
+ ctx.lineTo(obstacle.width/4, obstacle.height/2);
+ ctx.lineTo(obstacle.width/2, obstacle.height/3);
+ ctx.lineTo(obstacle.width/4, 0);
ctx.closePath();
ctx.fill();
- // 火焰效果
- ctx.fillStyle = 'orange';
+ // 尾翼
ctx.beginPath();
- ctx.moveTo(-missile.size / 2, -missile.size / 4);
- ctx.lineTo(-missile.size, 0);
- ctx.lineTo(-missile.size / 2, missile.size / 4);
+ ctx.moveTo(-obstacle.width/2, 0);
+ ctx.lineTo(-obstacle.width/3, -obstacle.height/4);
+ ctx.lineTo(-obstacle.width/4, -obstacle.height/4);
+ ctx.lineTo(-obstacle.width/3, 0);
ctx.closePath();
ctx.fill();
- ctx.restore();
- });
-
- // 绘制子弹
- gameState.bullets.forEach(bullet => {
- const gradient = ctx.createRadialGradient(
- bullet.x, bullet.y, 0,
- bullet.x, bullet.y, bullet.size
- );
- gradient.addColorStop(0, '#ff0');
- gradient.addColorStop(1, '#f80');
-
ctx.beginPath();
- ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
- ctx.fillStyle = gradient;
+ ctx.moveTo(-obstacle.width/2, 0);
+ ctx.lineTo(-obstacle.width/3, obstacle.height/4);
+ ctx.lineTo(-obstacle.width/4, obstacle.height/4);
+ ctx.lineTo(-obstacle.width/3, 0);
+ ctx.closePath();
ctx.fill();
- // 子弹尾迹
+ // 驾驶舱
+ ctx.fillStyle = '#3498db';
ctx.beginPath();
- ctx.moveTo(bullet.x - bullet.speed, bullet.y);
- ctx.lineTo(bullet.x, bullet.y);
- ctx.strokeStyle = 'rgba(255, 200, 0, 0.8)';
- ctx.lineWidth = bullet.size / 2;
- ctx.stroke();
- });
-
- // 绘制敌人子弹
- gameState.enemyBullets.forEach(bullet => {
- const gradient = ctx.createRadialGradient(
- bullet.x, bullet.y, 0,
- bullet.x, bullet.y, bullet.size
- );
- gradient.addColorStop(0, '#f00');
- gradient.addColorStop(1, '#800');
-
- ctx.beginPath();
- ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
- ctx.fillStyle = gradient;
+ ctx.arc(obstacle.width/4, 0, obstacle.width/8, 0, Math.PI * 2);
ctx.fill();
- // 子弹尾迹
- ctx.beginPath();
- ctx.moveTo(bullet.x + bullet.speed * Math.cos(bullet.angle), bullet.y + bullet.speed * Math.sin(bullet.angle));
- ctx.lineTo(bullet.x, bullet.y);
- ctx.strokeStyle = 'rgba(255, 100, 100, 0.8)';
- ctx.lineWidth = bullet.size / 2;
- ctx.stroke();
- });
-
- // 绘制星星
- gameState.stars.forEach(star => {
- ctx.save();
- ctx.translate(star.x, star.y);
- ctx.rotate(star.rotation);
+ // 如果是Boss,添加特殊标记
+ if (obstacle.isBoss) {
+ ctx.fillStyle = 'gold';
+ ctx.font = 'bold 20px Arial';
+ctx.textAlign = 'center';
+ctx.textBaseline = 'middle';
+ctx.fillText('BOSS', 0, 0);
+}
+} else {
+// 绘制普通矩形障碍物
+ctx.fillStyle = obstacle.isBoss ? '#8B0000' : (obstacle.isLarge ? '#333' : '#555');
+ctx.fillRect(
+-obstacle.width / 2,
+-obstacle.height / 2,
+obstacle.width,
+obstacle.height
+);
+ // 添加一些细节
+ ctx.fillStyle = obstacle.isBoss ? '#600000' : (obstacle.isLarge ? '#222' : '#444');
+ ctx.fillRect(
+ -obstacle.width / 2 + 5,
+ -obstacle.height / 2 + 5,
+ obstacle.width - 10,
+ obstacle.height - 10
+ );
- ctx.beginPath();
- for (let i = 0; i < 5; i++) {
- const angle = (i * 2 * Math.PI / 5) - Math.PI / 2;
- const innerAngle = angle + Math.PI / 5;
- const outerRadius = star.size / 2;
- const innerRadius = star.size / 4;
-
- if (i === 0) {
+ // 添加裂缝效果 (对于受损的大型障碍物)
+ if ((obstacle.isLarge || obstacle.isBoss) && obstacle.health < obstacle.maxHealth) {
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
+ ctx.lineWidth = 2;
+ for (let i = 0; i < (obstacle.isBoss ? 10 : 3); i++) {
+ ctx.beginPath();
ctx.moveTo(
- Math.cos(angle) * outerRadius,
- Math.sin(angle) * outerRadius
+ -obstacle.width / 2 + Math.random() * obstacle.width,
+ -obstacle.height / 2 + Math.random() * obstacle.height / 3
);
- } else {
ctx.lineTo(
- Math.cos(angle) * outerRadius,
- Math.sin(angle) * outerRadius
+ -obstacle.width / 2 + Math.random() * obstacle.width,
+ obstacle.height / 2 - Math.random() * obstacle.height / 3
);
+ ctx.stroke();
}
-
- ctx.lineTo(
- Math.cos(innerAngle) * innerRadius,
- Math.sin(innerAngle) * innerRadius
- );
}
- ctx.closePath();
-
- const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, star.size / 2);
- gradient.addColorStop(0, 'gold');
- gradient.addColorStop(1, 'yellow');
- ctx.fillStyle = gradient;
- ctx.shadowColor = 'yellow';
- ctx.shadowBlur = 10;
- ctx.fill();
-
- ctx.restore();
- });
-
- // 绘制障碍物
- gameState.obstacles.forEach(obstacle => {
- ctx.save();
- ctx.translate(obstacle.x, obstacle.y);
- if (obstacle.type === 'rectangle') {
- // 绘制健康条 (如果是矩形障碍物)
- if (obstacle.health < obstacle.maxHealth) {
- const healthBarWidth = obstacle.isBoss ? 100 : 20;
- ctx.fillStyle = 'red';
- ctx.fillRect(
- -healthBarWidth / 2,
- -obstacle.height / 2 - 15,
- healthBarWidth,
- 5
- );
- ctx.fillStyle = obstacle.isBoss ? 'purple' : 'lime';
- ctx.fillRect(
- -healthBarWidth / 2,
- -obstacle.height / 2 - 15,
- healthBarWidth * (obstacle.health / obstacle.maxHealth),
- 5
- );
- }
-
- // 绘制敌人飞机
- if (obstacle.canShoot) {
- // 飞机主体
- ctx.fillStyle = obstacle.isBoss ? '#8B0000' : '#333';
- ctx.beginPath();
- ctx.moveTo(-obstacle.width/2, 0);
- ctx.lineTo(obstacle.width/2, -obstacle.height/4);
- ctx.lineTo(obstacle.width/2, obstacle.height/4);
- ctx.closePath();
- ctx.fill();
-
- // 飞机机翼
- ctx.fillStyle = obstacle.isBoss ? '#600000' : '#222';
- ctx.beginPath();
- ctx.moveTo(-obstacle.width/4, 0);
- ctx.lineTo(0, -obstacle.height/2);
- ctx.lineTo(obstacle.width/4, -obstacle.height/4);
- ctx.lineTo(obstacle.width/4, obstacle.height/4);
- ctx.lineTo(0, obstacle.height/2);
- ctx.closePath();
- ctx.fill();
-
- // 飞机尾翼
- ctx.fillStyle = obstacle.isBoss ? '#400000' : '#111';
- ctx.beginPath();
- ctx.moveTo(-obstacle.width/2, 0);
- ctx.lineTo(-obstacle.width/2, -obstacle.height/4);
- ctx.lineTo(-obstacle.width/2 + 10, -obstacle.height/4);
- ctx.lineTo(-obstacle.width/4, 0);
- ctx.closePath();
- ctx.fill();
-
- ctx.beginPath();
- ctx.moveTo(-obstacle.width/2, 0);
- ctx.lineTo(-obstacle.width/2, obstacle.height/4);
- ctx.lineTo(-obstacle.width/2 + 10, obstacle.height/4);
- ctx.lineTo(-obstacle.width/4, 0);
- ctx.closePath();
- ctx.fill();
-
- // 如果是Boss,添加特殊标记
- if (obstacle.isBoss) {
- ctx.fillStyle = 'gold';
- ctx.font = 'bold 20px Arial';
- ctx.textAlign = 'center';
- ctx.textBaseline = 'middle';
- ctx.fillText('BOSS', 0, 0);
- }
- } else {
- // 绘制普通矩形障碍物
- ctx.fillStyle = obstacle.isBoss ? '#8B0000' : (obstacle.isLarge ? '#333' : '#555');
- ctx.fillRect(
- -obstacle.width / 2,
- -obstacle.height / 2,
- obstacle.width,
- obstacle.height
- );
-
- // 添加一些细节
- ctx.fillStyle = obstacle.isBoss ? '#600000' : (obstacle.isLarge ? '#222' : '#444');
- ctx.fillRect(
- -obstacle.width / 2 + 5,
- -obstacle.height / 2 + 5,
- obstacle.width - 10,
- obstacle.height - 10
- );
-
- // 添加裂缝效果 (对于受损的大型障碍物)
- if ((obstacle.isLarge || obstacle.isBoss) && obstacle.health < obstacle.maxHealth) {
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
- ctx.lineWidth = 2;
- for (let i = 0; i < (obstacle.isBoss ? 10 : 3); i++) {
- ctx.beginPath();
- ctx.moveTo(
- -obstacle.width / 2 + Math.random() * obstacle.width,
- -obstacle.height / 2 + Math.random() * obstacle.height / 3
- );
- ctx.lineTo(
- -obstacle.width / 2 + Math.random() * obstacle.width,
- obstacle.height / 2 - Math.random() * obstacle.height / 3
- );
- ctx.stroke();
- }
- }
-
- // 如果是Boss,添加特殊标记
- if (obstacle.isBoss) {
- ctx.fillStyle = 'gold';
- ctx.font = 'bold 20px Arial';
- ctx.textAlign = 'center';
- ctx.textBaseline = 'middle';
- ctx.fillText('BOSS', 0, 0);
- }
- }
- } else {
- // 圆形障碍物
- ctx.beginPath();
- ctx.arc(0, 0, obstacle.width / 2, 0, Math.PI * 2);
- ctx.fillStyle = '#555';
- ctx.fill();
-
- // 添加一些细节
- ctx.beginPath();
- ctx.arc(0, 0, obstacle.width / 2 - 5, 0, Math.PI * 2);
- ctx.fillStyle = '#444';
- ctx.fill();
-
- // 添加裂缝效果 (对于受损的大型障碍物)
- if (obstacle.isLarge && obstacle.health < obstacle.maxHealth) {
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
- ctx.lineWidth = 2;
- for (let i = 0; i < 3; i++) {
- ctx.beginPath();
- ctx.moveTo(
- Math.cos(i * 2) * obstacle.width / 4,
- Math.sin(i * 2) * obstacle.width / 4
- );
- ctx.lineTo(
- Math.cos(i * 2 + 1) * obstacle.width / 3,
- Math.sin(i * 2 + 1) * obstacle.width / 3
- );
- ctx.stroke();
- }
- }
+ // 如果是Boss,添加特殊标记
+ if (obstacle.isBoss) {
+ ctx.fillStyle = 'gold';
+ ctx.font = 'bold 20px Arial';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText('BOSS', 0, 0);
}
-
- ctx.restore();
- });
-
- // 绘制飞机
- ctx.save();
- ctx.translate(gameState.plane.x, gameState.plane.y);
- ctx.rotate(gameState.plane.rotation * Math.PI / 180);
-
- // 绘制保护罩
- if (gameState.plane.hasShield && gameState.plane.shieldDuration > Date.now()) {
- ctx.beginPath();
- ctx.arc(0, 0, 45, 0, Math.PI * 2);
- ctx.strokeStyle = `rgba(0, 204, 255, ${0.3 + Math.sin(Date.now() / 200) * 0.3})`;
- ctx.lineWidth = 3;
- ctx.stroke();
-
- // 保护罩光晕
- const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 45);
- gradient.addColorStop(0, 'rgba(0, 204, 255, 0.2)');
- gradient.addColorStop(1, 'rgba(0, 204, 255, 0)');
- ctx.fillStyle = gradient;
- ctx.fill();
}
-
- // 飞机主体
- ctx.beginPath();
- ctx.moveTo(30, 0);
- ctx.lineTo(-20, -15);
- ctx.lineTo(-25, 0);
- ctx.lineTo(-20, 15);
- ctx.closePath();
- ctx.fillStyle = '#e74c3c';
- ctx.fill();
-
- // 飞机窗户
+ } else {
+ // 圆形障碍物
ctx.beginPath();
- ctx.arc(10, 0, 5, 0, Math.PI * 2);
- ctx.fillStyle = '#3498db';
+ ctx.arc(0, 0, obstacle.width / 2, 0, Math.PI * 2);
+ ctx.fillStyle = '#555';
ctx.fill();
- // 飞机机翼
+ // 添加一些细节
ctx.beginPath();
- ctx.moveTo(5, 0);
- ctx.lineTo(-5, -20);
- ctx.lineTo(-15, -20);
- ctx.lineTo(-5, 0);
- ctx.closePath();
- ctx.fillStyle = '#c0392b';
+ ctx.arc(0, 0, obstacle.width / 2 - 5, 0, Math.PI * 2);
+ ctx.fillStyle = '#444';
ctx.fill();
- ctx.beginPath();
- ctx.moveTo(5, 0);
- ctx.lineTo(-5, 20);
- ctx.lineTo(-15, 20);
- ctx.lineTo(-5, 0);
- ctx.closePath();
- ctx.fillStyle = '#c0392b';
- ctx.fill();
-
- // 飞机尾翼
- ctx.beginPath();
- ctx.moveTo(-20, 0);
- ctx.lineTo(-25, -10);
- ctx.lineTo(-30, -10);
- ctx.lineTo(-25, 0);
- ctx.closePath();
- ctx.fillStyle = '#a5281b';
- ctx.fill();
-
- ctx.beginPath();
- ctx.moveTo(-20, 0);
- ctx.lineTo(-25, 10);
- ctx.lineTo(-30, 10);
- ctx.lineTo(-25, 0);
- ctx.closePath();
- ctx.fillStyle = '#a5281b';
- ctx.fill();
-
- ctx.restore();
-
- // 绘制爆炸效果
- gameState.explosions.forEach(explosion => {
- ctx.save();
- ctx.translate(explosion.x, explosion.y);
-
- const gradient = ctx.createRadialGradient(
- 0, 0, 0,
- 0, 0, explosion.size
- );
- gradient.addColorStop(0, `rgba(255, 100, 0, ${explosion.alpha})`);
- gradient.addColorStop(0.5, `rgba(255, 200, 0, ${explosion.alpha * 0.6})`);
- gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
-
- ctx.beginPath();
- ctx.arc(0, 0, explosion.size, 0, Math.PI * 2);
- ctx.fillStyle = gradient;
- ctx.fill();
-
- ctx.restore();
- });
-
- // 绘制特效文字
- gameState.effects.forEach(effect => {
- const timePassed = Date.now() - effect.startTime;
- const progress = timePassed / effect.duration;
-
- ctx.save();
- ctx.translate(effect.x, effect.y - progress * 50); // 文字向上移动
- ctx.globalAlpha = 1 - progress * 0.8;
- ctx.font = 'bold 20px Arial';
- ctx.fillStyle = effect.color;
- ctx.textAlign = 'center';
- ctx.textBaseline = 'middle';
- ctx.fillText(effect.text, 0, 0);
-
- ctx.restore();
- });
-
- // 绘制速度线
- if (gameState.speed > 120) {
- for (let i = 0; i < 10; i++) {
- const x = Math.random() * canvas.width;
- const y = Math.random() * canvas.height;
- const length = Math.random() * 20 + 10;
- const angle = Math.atan2(
- gameState.plane.y - y,
- gameState.plane.x - x
- );
-
- ctx.save();
- ctx.translate(x, y);
- ctx.rotate(angle);
-
+ // 添加裂缝效果 (对于受损的大型障碍物)
+ if (obstacle.isLarge && obstacle.health < obstacle.maxHealth) {
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
+ ctx.lineWidth = 2;
+ for (let i = 0; i < 3; i++) {
ctx.beginPath();
- ctx.moveTo(0, 0);
- ctx.lineTo(length, 0);
- ctx.strokeStyle = `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.3})`;
- ctx.lineWidth = 1;
+ ctx.moveTo(
+ Math.cos(i * 2) * obstacle.width / 4,
+ Math.sin(i * 2) * obstacle.width / 4
+ );
+ ctx.lineTo(
+ Math.cos(i * 2 + 1) * obstacle.width / 3,
+ Math.sin(i * 2 + 1) * obstacle.width / 3
+ );
ctx.stroke();
-
- ctx.restore();
}
}
-
- // 绘制难度提示
- if (gameState.difficulty > 1.5) {
- ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
- ctx.font = '20px Arial';
- ctx.textAlign = 'right';
- ctx.fillText(`难度: ${gameState.difficulty.toFixed(1)}x`, canvas.width - 20, 30);
- }
- }
-
- // 辅助函数: 获取FontAwesome图标的Unicode
- function getIconCode(iconClass) {
- const icons = {
- 'fas fa-bolt': 'f0e7',
- 'fas fa-rocket': 'f135',
- 'fas fa-shield-alt': 'f3ed',
- 'fas fa-heart': 'f004',
- 'fas fa-clock': 'f017',
- 'fas fa-bomb': 'f1e2',
- 'fas fa-star': 'f005'
- };
- return icons[iconClass] || 'f128'; // 默认返回问号图标
}
-
- // 虚拟摇杆控制
- function setupJoystick() {
- const joystickArea = joystick;
- const handle = joystickHandle;
- let active = false;
- let startX = 0;
- let startY = 0;
- let handleX = 0;
- let handleY = 0;
- const maxDistance = 40;
-
- joystickArea.addEventListener('touchstart', (e) => {
- e.preventDefault();
- const touch = e.touches[0];
- const rect = joystickArea.getBoundingClientRect();
- startX = rect.left + rect.width / 2;
- startY = rect.top + rect.height / 2;
- handleX = touch.clientX - startX;
- handleY = touch.clientY - startY;
-
- // 限制摇杆移动范围
- const distance = Math.sqrt(handleX * handleX + handleY * handleY);
- if (distance > maxDistance) {
- handleX = (handleX / distance) * maxDistance;
- handleY = (handleY / distance) * maxDistance;
- }
-
- handle.style.transform = `translate(${handleX}px, ${handleY}px)`;
-
- // 计算角度和距离
- gameState.joystickAngle = Math.atan2(handleY, handleX);
- gameState.joystickDistance = distance / maxDistance;
- gameState.joystickActive = true;
- active = true;
- });
-
- joystickArea.addEventListener('touchmove', (e) => {
- if (!active) return;
- e.preventDefault();
- const touch = e.touches[0];
- handleX = touch.clientX - startX;
- handleY = touch.clientY - startY;
-
- // 限制摇杆移动范围
- const distance = Math.sqrt(handleX * handleX + handleY * handleY);
- if (distance > maxDistance) {
- handleX = (handleX / distance) * maxDistance;
- handleY = (handleY / distance) * maxDistance;
- }
-
- handle.style.transform = `translate(${handleX}px, ${handleY}px)`;
-
- // 计算角度和距离
- gameState.joystickAngle = Math.atan2(handleY, handleX);
- gameState.joystickDistance = distance / maxDistance;
- });
-
- joystickArea.addEventListener('touchend', (e) => {
- e.preventDefault();
- handle.style.transform = 'translate(0, 0)';
- gameState.joystickActive = false;
- active = false;
- });
- }
-
- // 事件监听
- window.addEventListener('resize', resizeCanvas);
- // 键盘控制
- document.addEventListener('keydown', (e) => {
- if (gameState.keys.hasOwnProperty(e.key)) {
- gameState.keys[e.key] = true;
- e.preventDefault();
- }
-
- if (e.key === ' ' || e.key === 'Spacebar') { // 空格键射击
- gameState.keys.Space = true;
- e.preventDefault();
- }
- });
+ ctx.restore();
+ });
+
+ // 绘制飞机
+ ctx.save();
+ ctx.translate(gameState.plane.x, gameState.plane.y);
+ ctx.rotate(gameState.plane.rotation * Math.PI / 180);
+
+ // 绘制保护罩
+ if (gameState.plane.hasShield && gameState.plane.shieldDuration > Date.now()) {
+ ctx.beginPath();
+ ctx.arc(0, 0, 45, 0, Math.PI * 2);
+ ctx.strokeStyle = `rgba(0, 204, 255, ${0.3 + Math.sin(Date.now() / 200) * 0.3})`;
+ ctx.lineWidth = 3;
+ ctx.stroke();
- document.addEventListener('keyup', (e) => {
- if (gameState.keys.hasOwnProperty(e.key)) {
- gameState.keys[e.key] = false;
- e.preventDefault();
- }
-
- if (e.key === ' ' || e.key === 'Spacebar') {
- gameState.keys.Space = false;
- e.preventDefault();
- }
- });
+ // 保护罩光晕
+ const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, 45);
+ gradient.addColorStop(0, 'rgba(0, 204, 255, 0.2)');
+ gradient.addColorStop(1, 'rgba(0, 204, 255, 0)');
+ ctx.fillStyle = gradient;
+ ctx.fill();
+ }
+
+ // 飞机主体
+ ctx.beginPath();
+ ctx.moveTo(30, 0);
+ ctx.lineTo(-20, -15);
+ ctx.lineTo(-25, 0);
+ ctx.lineTo(-20, 15);
+ ctx.closePath();
+ ctx.fillStyle = '#e74c3c';
+ ctx.fill();
+
+ // 飞机窗户
+ ctx.beginPath();
+ ctx.arc(10, 0, 5, 0, Math.PI * 2);
+ ctx.fillStyle = '#3498db';
+ ctx.fill();
+
+ // 飞机机翼
+ ctx.beginPath();
+ ctx.moveTo(5, 0);
+ ctx.lineTo(-5, -20);
+ ctx.lineTo(-15, -20);
+ ctx.lineTo(-5, 0);
+ ctx.closePath();
+ ctx.fillStyle = '#c0392b';
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(5, 0);
+ ctx.lineTo(-5, 20);
+ ctx.lineTo(-15, 20);
+ ctx.lineTo(-5, 0);
+ ctx.closePath();
+ ctx.fillStyle = '#c0392b';
+ ctx.fill();
+
+ // 飞机尾翼
+ ctx.beginPath();
+ ctx.moveTo(-20, 0);
+ ctx.lineTo(-25, -10);
+ ctx.lineTo(-30, -10);
+ ctx.lineTo(-25, 0);
+ ctx.closePath();
+ ctx.fillStyle = '#a5281b';
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(-20, 0);
+ ctx.lineTo(-25, 10);
+ ctx.lineTo(-30, 10);
+ ctx.lineTo(-25, 0);
+ ctx.closePath();
+ ctx.fillStyle = '#a5281b';
+ ctx.fill();
+
+ ctx.restore();
+
+ // 绘制爆炸效果
+ gameState.explosions.forEach(explosion => {
+ ctx.save();
+ ctx.translate(explosion.x, explosion.y);
- // 触摸控制按钮事件
- leftBtn.addEventListener('touchstart', (e) => {
- e.preventDefault();
- gameState.keys.ArrowLeft = true;
- });
- leftBtn.addEventListener('touchend', (e) => {
- e.preventDefault();
- gameState.keys.ArrowLeft = false;
- });
+ const gradient = ctx.createRadialGradient(
+ 0, 0, 0,
+ 0, 0, explosion.size
+ );
+ gradient.addColorStop(0, `rgba(255, 100, 0, ${explosion.alpha})`);
+ gradient.addColorStop(0.5, `rgba(255, 200, 0, ${explosion.alpha * 0.6})`);
+ gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
- rightBtn.addEventListener('touchstart', (e) => {
- e.preventDefault();
- gameState.keys.ArrowRight = true;
- });
- rightBtn.addEventListener('touchend', (e) => {
- e.preventDefault();
- gameState.keys.ArrowRight = false;
- });
+ ctx.beginPath();
+ ctx.arc(0, 0, explosion.size, 0, Math.PI * 2);
+ ctx.fillStyle = gradient;
+ ctx.fill();
- upBtn.addEventListener('touchstart', (e) => {
- e.preventDefault();
- gameState.keys.ArrowUp = true;
- });
- upBtn.addEventListener('touchend', (e) => {
- e.preventDefault();
- gameState.keys.ArrowUp = false;
- });
-
- downBtn.addEventListener('touchstart', (e) => {
- e.preventDefault();
- gameState.keys.ArrowDown = true;
- });
- downBtn.addEventListener('touchend', (e) => {
- e.preventDefault();
- gameState.keys.ArrowDown = false;
- });
-
- fireBtn.addEventListener('touchstart', (e) => {
- e.preventDefault();
- gameState.isFiring = true;
- });
- fireBtn.addEventListener('touchend', (e) => {
- e.preventDefault();
- gameState.isFiring = false;
- });
+ ctx.restore();
+ });
+
+ // 绘制特效文字
+ gameState.effects.forEach(effect => {
+ const timePassed = Date.now() - effect.startTime;
+ const progress = timePassed / effect.duration;
- // 鼠标控制按钮事件(用于桌面浏览器测试)
- leftBtn.addEventListener('mousedown', (e) => {
- e.preventDefault();
- gameState.keys.ArrowLeft = true;
- });
- leftBtn.addEventListener('mouseup', (e) => {
- e.preventDefault();
- gameState.keys.ArrowLeft = false;
- });
- leftBtn.addEventListener('mouseleave', (e) => {
- e.preventDefault();
- gameState.keys.ArrowLeft = false;
- });
+ ctx.save();
+ ctx.translate(effect.x, effect.y - progress * 50); // 文字向上移动
+ ctx.globalAlpha = 1 - progress * 0.8;
+
+ ctx.font = 'bold 20px Arial';
+ ctx.fillStyle = effect.color;
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(effect.text, 0, 0);
- rightBtn.addEventListener('mousedown', (e) => {
- e.preventDefault();
- gameState.keys.ArrowRight = true;
- });
- rightBtn.addEventListener('mouseup', (e) => {
- e.preventDefault();
- gameState.keys.ArrowRight = false;
- });
- rightBtn.addEventListener('mouseleave', (e) => {
- e.preventDefault();
- gameState.keys.ArrowRight = false;
- });
+ ctx.restore();
+ });
+
+ // 绘制速度线
+ if (gameState.speed > 120) {
+ for (let i = 0; i < 10; i++) {
+ const x = Math.random() * canvas.width;
+ const y = Math.random() * canvas.height;
+ const length = Math.random() * 20 + 10;
+ const angle = Math.atan2(
+ gameState.plane.y - y,
+ gameState.plane.x - x
+ );
+
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(angle);
+
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(length, 0);
+ ctx.strokeStyle = `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.3})`;
+ ctx.lineWidth = 1;
+ ctx.stroke();
+
+ ctx.restore();
+ }
+ }
+
+ // 绘制难度提示
+ if (gameState.difficulty > 1.5) {
+ ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
+ ctx.font = '20px Arial';
+ ctx.textAlign = 'right';
+ ctx.fillText(`难度: ${gameState.difficulty.toFixed(1)}x`, canvas.width - 20, 30);
+ }
+}
+
+// 辅助函数: 获取FontAwesome图标的Unicode
+function getIconCode(iconClass) {
+ const icons = {
+ 'fas fa-bolt': 'f0e7',
+ 'fas fa-rocket': 'f135',
+ 'fas fa-shield-alt': 'f3ed',
+ 'fas fa-heart': 'f004',
+ 'fas fa-clock': 'f017',
+ 'fas fa-bomb': 'f1e2',
+ 'fas fa-star': 'f005'
+ };
+ return icons[iconClass] || 'f128'; // 默认返回问号图标
+}
+
+// 虚拟摇杆控制
+function setupJoystick() {
+ const joystickArea = joystick;
+ const handle = joystickHandle;
+ let active = false;
+ let startX = 0;
+ let startY = 0;
+ let handleX = 0;
+ let handleY = 0;
+ const maxDistance = 40;
+
+ joystickArea.addEventListener('touchstart', (e) => {
+ e.preventDefault();
+ const touch = e.touches[0];
+ const rect = joystickArea.getBoundingClientRect();
+ startX = rect.left + rect.width / 2;
+ startY = rect.top + rect.height / 2;
+ handleX = touch.clientX - startX;
+ handleY = touch.clientY - startY;
- upBtn.addEventListener('mousedown', (e) => {
- e.preventDefault();
- gameState.keys.ArrowUp = true;
- });
- upBtn.addEventListener('mouseup', (e) => {
- e.preventDefault();
- gameState.keys.ArrowUp = false;
- });
- upBtn.addEventListener('mouseleave', (e) => {
- e.preventDefault();
- gameState.keys.ArrowUp = false;
- });
+ // 限制摇杆移动范围
+ const distance = Math.sqrt(handleX * handleX + handleY * handleY);
+ if (distance > maxDistance) {
+ handleX = (handleX / distance) * maxDistance;
+ handleY = (handleY / distance) * maxDistance;
+ }
- downBtn.addEventListener('mousedown', (e) => {
- e.preventDefault();
- gameState.keys.ArrowDown = true;
- });
- downBtn.addEventListener('mouseup', (e) => {
- e.preventDefault();
- gameState.keys.ArrowDown = false;
- });
- downBtn.addEventListener('mouseleave', (e) => {
- e.preventDefault();
- gameState.keys.ArrowDown = false;
- });
+ handle.style.transform = `translate(${handleX}px, ${handleY}px)`;
- fireBtn.addEventListener('mousedown', (e) => {
- e.preventDefault();
- gameState.isFiring = true;
- });
- fireBtn.addEventListener('mouseup', (e) => {
- e.preventDefault();
- gameState.isFiring = false;
- });
- fireBtn.addEventListener('mouseleave', (e) => {
- e.preventDefault();
- gameState.isFiring = false;
- });
+ // 计算角度和距离
+ gameState.joystickAngle = Math.atan2(handleY, handleX);
+ gameState.joystickDistance = distance / maxDistance;
+ gameState.joystickActive = true;
+ active = true;
+ });
+
+ joystickArea.addEventListener('touchmove', (e) => {
+ if (!active) return;
+ e.preventDefault();
+ const touch = e.touches[0];
+ handleX = touch.clientX - startX;
+ handleY = touch.clientY - startY;
- // 按钮事件
- startButton.addEventListener('click', initGame);
- restartButton.addEventListener('click', initGame);
+ // 限制摇杆移动范围
+ const distance = Math.sqrt(handleX * handleX + handleY * handleY);
+ if (distance > maxDistance) {
+ handleX = (handleX / distance) * maxDistance;
+ handleY = (handleY / distance) * maxDistance;
+ }
- // 初始调整画布大小
- resizeCanvas();
- setupJoystick();
+ handle.style.transform = `translate(${handleX}px, ${handleY}px)`;
- // 显示最高分
- highScoreDisplay.textContent = gameState.highScore;
-
- Made with
DeepSite - 🧬 Remix
-