'use client'; import React, { useState, useEffect, useRef, useMemo } from 'react'; // 常量定义 const VIEW_WIDTH = 1000; const VIEW_HEIGHT = 600; const FPS = 60; const PLAYER_SPEED = 4; const LASER_SPEED = 12; const ENEMY_SPEED = 2.5; const SPAWN_RATE = 0.02; // 颜色定义 const COLORS = { bg: '#0f172a', player: '#38bdf8', // 天蓝 playerLaser: '#ef4444', // 义军红色激光 enemy: '#94a3b8', // 帝国灰 enemyLaser: '#22c55e', // 帝国绿色激光 star: '#ffffff', hud: '#0ea5e9', explosion: '#fbbf24', }; // 类型定义 type Entity = { id: number; x: number; y: number; width: number; height: number; vx: number; vy: number; hp: number; maxHp: number; type?: 'fighter' | 'interceptor'; }; type Projectile = { id: number; x: number; y: number; vx: number; vy: number; isPlayer: boolean; }; type Particle = { id: number; x: number; y: number; vx: number; vy: number; life: number; maxLife: number; size: number; color: string; }; type Star = { id: number; x: number; y: number; size: number; speed: number; opacity: number; }; export default function StarWarsBattleAnimation() { // 游戏状态 const [player, setPlayer] = useState({ id: 0, x: VIEW_WIDTH / 2, y: VIEW_HEIGHT - 80, width: 40, height: 40, vx: 0, vy: 0, hp: 100, maxHp: 100 }); const [enemies, setEnemies] = useState([]); const [projectiles, setProjectiles] = useState([]); const [particles, setParticles] = useState([]); const [stars, setStars] = useState([]); const [score, setScore] = useState(0); const [gameTime, setGameTime] = useState(0); const [shake, setShake] = useState(0); // Refs needed for the loop to access latest state without re-triggering effect constantly const stateRef = useRef({ player, enemies, projectiles, particles, stars, score, gameTime, shake }); // 同步 Ref useEffect(() => { stateRef.current = { player, enemies, projectiles, particles, stars, score, gameTime, shake }; }, [player, enemies, projectiles, particles, stars, score, gameTime, shake]); // 初始化星空 useEffect(() => { const initialStars = Array.from({ length: 100 }, (_, i) => ({ id: i, x: Math.random() * VIEW_WIDTH, y: Math.random() * VIEW_HEIGHT, size: Math.random() * 2 + 0.5, speed: Math.random() * 3 + 0.5, opacity: Math.random() })); setStars(initialStars); }, []); // 游戏主循环 useEffect(() => { let animationFrameId: number; let lastId = 0; const loop = () => { const state = stateRef.current; let { player, enemies, projectiles, particles, stars, score, gameTime, shake } = state; // 1. 更新星空 (视差滚动) const nextStars = stars.map(star => { let newY = star.y + star.speed * (shake > 0 ? 5 : 1); // 加速效果 if (newY > VIEW_HEIGHT) newY = 0; return { ...star, y: newY }; }); // 2. 玩家自动驾驶逻辑 (模拟AI) // 简单的正弦波运动加上趋向屏幕中心的力 const time = Date.now() / 1000; const targetX = (VIEW_WIDTH / 2) + Math.sin(time) * 300; const dx = targetX - player.x; player.vx = dx * 0.05; player.x += player.vx; // 限制玩家边界 if (player.x < 50) player.x = 50; if (player.x > VIEW_WIDTH - 50) player.x = VIEW_WIDTH - 50; // 玩家自动射击 if (gameTime % 15 === 0) { lastId++; projectiles.push({ id: lastId, x: player.x, y: player.y - 20, vx: 0, vy: -LASER_SPEED, isPlayer: true }); // 双管齐射 lastId++; projectiles.push({ id: lastId, x: player.x - 20, y: player.y - 10, vx: -1, vy: -LASER_SPEED, isPlayer: true }); lastId++; projectiles.push({ id: lastId, x: player.x + 20, y: player.y - 10, vx: 1, vy: -LASER_SPEED, isPlayer: true }); } // 3. 敌人生成 if (Math.random() < SPAWN_RATE) { lastId++; const type = Math.random() > 0.7 ? 'interceptor' : 'fighter'; enemies.push({ id: lastId, x: Math.random() * (VIEW_WIDTH - 100) + 50, y: -50, width: type === 'interceptor' ? 30 : 40, height: 40, vx: (Math.random() - 0.5) * 2, vy: ENEMY_SPEED * (type === 'interceptor' ? 1.5 : 1), hp: type === 'interceptor' ? 20 : 40, maxHp: type === 'interceptor' ? 20 : 40, type: type as any }); } // 4. 敌人逻辑 enemies = enemies.map(enemy => { // 移动 let newX = enemy.x + enemy.vx + Math.sin(gameTime * 0.1 + enemy.id) * 2; let newY = enemy.y + enemy.vy; // 敌人射击 logic if (Math.random() < 0.02 && newY < VIEW_HEIGHT - 200) { lastId++; projectiles.push({ id: lastId, x: newX, y: newY + 20, vx: (player.x - newX) * 0.01, // 瞄准玩家 vy: LASER_SPEED * 0.6, isPlayer: false }); } return { ...enemy, x: newX, y: newY }; }).filter(e => e.y < VIEW_HEIGHT + 100); // 5. 子弹移动 projectiles = projectiles.map(p => ({ ...p, x: p.x + p.vx, y: p.y + p.vy })).filter(p => p.y > -50 && p.y < VIEW_HEIGHT + 50); // 6. 碰撞检测 const nextParticles = [...particles]; const hits: number[] = []; // store projectile IDs to remove let newScore = score; let newShake = Math.max(0, shake - 1); // 玩家子弹击中敌人 projectiles.forEach(p => { if (p.isPlayer) { enemies.forEach(e => { if (Math.abs(p.x - e.x) < e.width && Math.abs(p.y - e.y) < e.height) { hits.push(p.id); e.hp -= 10; // 击中特效 for(let i=0; i<3; i++) { lastId++; nextParticles.push({ id: lastId, x: p.x, y: p.y, vx: (Math.random()-0.5)*5, vy: (Math.random()-0.5)*5, life: 20, maxLife: 20, size: Math.random()*3+1, color: COLORS.enemyLaser }); } if (e.hp <= 0) { newScore += e.type === 'interceptor' ? 150 : 100; newShake = 5; // 屏幕震动 // 爆炸特效 for(let i=0; i<15; i++) { lastId++; nextParticles.push({ id: lastId, x: e.x, y: e.y, vx: (Math.random()-0.5)*10, vy: (Math.random()-0.5)*10, life: 40, maxLife: 40, size: Math.random()*5+2, color: COLORS.explosion }); } } } }); } else { // 敌人子弹击中玩家 if (Math.abs(p.x - player.x) < player.width && Math.abs(p.y - player.y) < player.height) { hits.push(p.id); player.hp -= 5; newShake = 10; // 玩家受击特效 for(let i=0; i<5; i++) { lastId++; nextParticles.push({ id: lastId, x: p.x, y: p.y, vx: (Math.random()-0.5)*8, vy: (Math.random()-0.5)*8, life: 30, maxLife: 30, size: Math.random()*3, color: COLORS.player }); } } } }); // 移除死亡实体 const livingEnemies = enemies.filter(e => e.hp > 0); const livingProjectiles = projectiles.filter(p => !hits.includes(p.id)); // 7. 粒子更新 const activeParticles = nextParticles.map(p => ({ ...p, x: p.x + p.vx, y: p.y + p.vy, life: p.life - 1 })).filter(p => p.life > 0); // 玩家护盾恢复 if (gameTime % 60 === 0 && player.hp < 100) player.hp += 1; if (player.hp <= 0) player.hp = 100; // 演示模式不死 // 更新 State setStars(nextStars); setPlayer({ ...player }); setEnemies(livingEnemies); setProjectiles(livingProjectiles); setParticles(activeParticles); setScore(newScore); setGameTime(gameTime + 1); setShake(newShake); animationFrameId = requestAnimationFrame(loop); }; animationFrameId = requestAnimationFrame(loop); return () => cancelAnimationFrame(animationFrameId); }, []); // Empty dependency array for single loop setup // Shake transform const shakeStyle = shake > 0 ? `translate(${(Math.random()-0.5)*shake}px, ${(Math.random()-0.5)*shake}px)` : ''; return (
{/* 辉光滤镜 */} {/* 渐变 */} {/* 1. 星空背景 */} {stars.map((star) => ( ))} {/* 2. 粒子效果 (放在飞船下方) */} {particles.map((p) => ( ))} {/* 3. 敌机 */} {enemies.map((enemy) => ( {/* TIE Fighter 风格 */} {enemy.type === 'fighter' ? ( {/* Left Wing */} {/* Right Wing */} {/* Cockpit */} {/* Engine Glow */} ) : ( {/* Interceptor 风格 (Pointy wings) */} )} {/* 敌机血条 */} {/* 锁定框 UI */} ))} {/* 4. 玩家飞船 */} {/* 引擎尾焰 */} {/* 机身 (X-Wing 风格抽象) */} {/* Guns Left */} {/* Guns Right */} {/* Cockpit glass */} {/* 红色涂装 */} {/* 护盾特效 (受击时显示) */} {player.hp < 100 && ( )} {/* 5. 子弹 */} {projectiles.map((p) => ( ))} {/* 6. HUD 界面 (科技感图层) */} {/* 顶部状态栏 */} 得分 SCORE {score.toString().padStart(6, '0')} 系统 SYSTEM ONLINE {/* 底部仪表盘 */} {/* 左下角护盾信息 */} 护盾 SHIELD 30 ? "#0ea5e9" : "#ef4444"} rx="2" filter="url(#glow)" /> {/* 右下角武器信息 */} 武器 WEAPON READY {/* 瞄准准星 (跟随玩家稍微延迟) */} {/* 装饰性网格线 */} {/* 覆盖层文字 - 增加电影感 */}
T-65 X-WING STARFIGHTER // SIMULATION LOG: {gameTime}
); }