🎮ArcadeLab

深空舰队 - 终极战术模拟

by EpicCoder88
624 lines21.5 KB
▶ Play
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>深空舰队 - 终极战术模拟</title>
<style>
  body { margin: 0; overflow: hidden; background: #050914; color: #fff; font-family: 'Courier New', Courier, monospace; touch-action: none; }
  canvas { display: block; width: 100vw; height: 100vh; }
  
  /* 战前配置界面 UI */
  #menu {
    position: absolute; top: 0; left: 0; width: 100vw; height: 100vh;
    background: rgba(5, 9, 20, 0.95); display: flex; flex-direction: column;
    align-items: center; justify-content: center; z-index: 10;
  }
  #menu h1 { color: #66ccff; text-shadow: 0 0 10px #66ccff; font-size: 28px; margin-bottom: 5px; }
  #menu p { color: #8899aa; font-size: 12px; margin-bottom: 30px; }
  
  .config-row { display: flex; align-items: center; margin: 8px 0; background: #0a1020; padding: 8px 15px; border-radius: 6px; border: 1px solid #1a3050; width: 260px; justify-content: space-between;}
  .config-row span { font-size: 14px; }
  .config-row .name.blue { color: #66ccff; }
  .config-row .name.red { color: #ff3366; }
  
  .btn { background: #1a3050; color: #fff; border: 1px solid #336699; padding: 5px 12px; margin: 0 5px; border-radius: 4px; cursor: pointer; font-size: 16px; user-select: none; }
  .btn:active { background: #336699; }
  
  #startBtn {
    margin-top: 30px; padding: 12px 40px; font-size: 20px; font-weight: bold;
    background: #66ccff; color: #000; border: none; border-radius: 8px;
    box-shadow: 0 0 15px #66ccff; cursor: pointer;
  }
  #startBtn:active { transform: scale(0.95); }
</style>
</head>
<body>

<div id="menu">
  <h1>深空舰队战术模拟</h1>
  <p>指挥官,请配置双方舰队阵容</p>
  
  <div id="config-container">
    <!-- JS动态生成配置列表 -->
  </div>
  
  <button id="startBtn">开 战</button>
</div>

<canvas id="gameCanvas"></canvas>

<script>
// ==========================================
// 1. 基础设置与数学工具
// ==========================================
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let W, H;

function resize() {
  W = canvas.width = window.innerWidth;
  H = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize); resize();

const dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
const angleTo = (a, b) => Math.atan2(b.y - a.y, b.x - a.x);
const normAngle = (a) => {
  while (a > Math.PI) a -= Math.PI * 2;
  while (a < -Math.PI) a += Math.PI * 2;
  return a;
};

let entities = [];
let bullets = [];
let particles = [];
let isGameRunning = false;

// ==========================================
// 2. 实体基类与物理系统 (根据手稿:推进单向推力,转向角速度)
// ==========================================
class Ship {
  constructor(x, y, color, isEnemy) {
    this.x = x; this.y = y;
    this.vx = 0; this.vy = 0;
    this.angle = isEnemy ? Math.PI : 0; // 朝向
    this.color = color;
    this.isEnemy = isEnemy;
    this.dead = false;
    
    // 手稿数值映射:默认基准值
    this.turnRate = 2 / 60; // rad/s 转换到每帧
    this.thrustAccel = 400 / 60; // xp/s 转换到每帧加速度
    this.maxSpeed = 300 / 60;
    this.detectRange = 2000;
    this.radius = 20; 
    
    this.hp = 100; this.maxHp = 100;
    this.fireCooldown = 0;
    this.pdCooldown = 0; // 近防炮冷却
    this.aiState = 'idle'; 
    this.target = null;
    this.engineParticles = 0;
  }

  update() {
    if (this.dead) return;
    
    // 速度阻尼,模拟太空摩擦 (避免无限滑行太远)
    this.vx *= 0.985; this.vy *= 0.985;

    if (this.fireCooldown > 0) this.fireCooldown--;
    if (this.pdCooldown > 0) this.pdCooldown--;

    // 敌我识别与索敌
    this.target = this.findTarget();

    if (this.target) {
      this.combatLogic();
    } else {
      // 无目标随机游走
      if (Math.random() < 0.02) this.angle += (Math.random() - 0.5);
      this.applyThrust();
    }

    // 位移更新
    this.x += this.vx; this.y += this.vy;

    // 边界处理 (反弹)
    if (this.x < 30) { this.x = 30; this.vx = Math.abs(this.vx); }
    if (this.x > W - 30) { this.x = W - 30; this.vx = -Math.abs(this.vx); }
    if (this.y < 30) { this.y = 30; this.vy = Math.abs(this.vy); }
    if (this.y > H - 30) { this.y = H - 30; this.vy = -Math.abs(this.vy); }
    
    // 绘制引擎尾焰粒子
    if (Math.hypot(this.vx, this.vy) > 0.5 && this.engineParticles++ % 2 === 0) {
       particles.push({ x: this.x - Math.cos(this.angle)*15, y: this.y - Math.sin(this.angle)*15,
         vx: -this.vx*0.5 + (Math.random()-0.5), vy: -this.vy*0.5 + (Math.random()-0.5),
         life: 15, maxLife: 15, color: this.color, size: 2 });
    }
  }

  findTarget() {
    let closest = null; let minDist = this.detectRange;
    for (let e of entities) {
      if (!e.dead && e.isEnemy !== this.isEnemy) {
        let d = dist(this, e);
        if (d < minDist) { minDist = d; closest = e; }
      }
    }
    return closest;
  }

  // 转向并推进 (手稿:推进器只能推向一个方向)
  applyThrust() {
    this.vx += Math.cos(this.angle) * (this.thrustAccel / 20);
    this.vy += Math.sin(this.angle) * (this.thrustAccel / 20);
    
    // 限速
    let sp = Math.hypot(this.vx, this.vy);
    if (sp > this.maxSpeed) {
      this.vx = (this.vx / sp) * this.maxSpeed;
      this.vy = (this.vy / sp) * this.maxSpeed;
    }
  }

  // 基础战斗逻辑 (会被子类重写)
  combatLogic() {
    let tAng = angleTo(this, this.target);
    let diff = normAngle(tAng - this.angle);
    
    // 转向
    this.angle += Math.sign(diff) * Math.min(Math.abs(diff), this.turnRate);
    
    // 保持距离与规避
    if (dist(this, this.target) > 600) {
      this.applyThrust(); // 远则靠近
    } else {
      this.applyThrust(); // 近则也稍微推进以保持机动
    }
  }

  drawHealthBar() {
    ctx.fillStyle = 'rgba(0,0,0,0.6)';
    ctx.fillRect(-20, 25, 40, 4);
    ctx.fillStyle = this.isEnemy ? '#ff3366' : '#66ccff';
    ctx.fillRect(-20, 25, 40 * Math.max(0, this.hp / this.maxHp), 4);
  }
}

// ==========================================
// 3. 具体舰船建模与机制 (完全依照手稿)
// ==========================================

// 【激光舰】: 线型, 5舱, 太阳能板x2, 大功率舰艏激光炮, 4门拦截炮
class LaserShip extends Ship {
  constructor(x, y, isEnemy) {
    super(x, y, isEnemy ? '#ff88aa' : '#66ccff', isEnemy);
    this.type = 'laser';
    this.radius = 25;
    this.turnRate = 2 / 60; this.thrustAccel = 200 / 60; this.maxSpeed = 150 / 60;
    this.fireCooldown = 0;
    this.heat = 0; // 大炮热量 (开火30s过热)
  }
  combatLogic() {
    super.combatLogic();
    let t = this.target;
    let aimDiff = Math.abs(normAngle(angleTo(this, t) - this.angle));
    
    // 主炮开火 (需对准,连续开火)
    if (this.heat < 100) {
      if (aimDiff < 0.1 && this.fireCooldown <= 0) {
        bullets.push(new Bullet(this.x, this.y, this.angle, this.isEnemy, 'heavy_laser'));
        this.fireCooldown = 10;
        this.heat += 2.5; // 逐渐升温,约30秒过热
      }
    } else {
      this.heat -= 0.5; // 散热
    }

    // 点射拦截炮 (自动开火拦截导弹)
    if (this.pdCooldown <= 0) {
      for (let b of bullets) {
        if (b.isEnemy !== this.isEnemy && b.type === 'missile') {
          if (dist(this, b) < 300) {
            let bAng = angleTo(this, b);
            bullets.push(new Bullet(this.x, this.y, bAng, this.isEnemy, 'pd_laser'));
            this.pdCooldown = 10;
            break;
          }
        }
      }
    }
  }
  draw() {
    ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle);
    // 线型主体 (5个舱室示意)
    ctx.fillStyle = this.color; ctx.fillRect(-30, -8, 60, 16); 
    // 太阳能板 (x2)
    ctx.fillStyle = '#112244'; ctx.fillRect(-15, -30, 25, 20); ctx.fillRect(-15, 10, 25, 20);
    // 核心舱/武器舱
    ctx.fillStyle = '#ffffff'; ctx.fillRect(15, -4, 12, 8);
    // 舰艏大功率激光炮
    ctx.fillStyle = '#00ffff';
    ctx.fillRect(27, -1, 10, 2);
    if (this.heat > 100) { ctx.fillStyle = 'rgba(255,0,0,0.5)'; ctx.fillRect(27, -3, 10, 6); }
    ctx.restore();
    this.drawHealthBar();
    if (this.heat > 100) { ctx.fillStyle = 'red'; ctx.font='10px Arial'; ctx.fillText('过热', this.x-10, this.y-35); }
  }
}

// 【突击舰】: 十字型, 7舱, 电磁轨道炮x2, 近防炮, 导弹
class AssaultShip extends Ship {
  constructor(x, y, isEnemy) {
    super(x, y, isEnemy ? '#ffaa00' : '#00ffcc', isEnemy);
    this.type = 'assault';
    this.radius = 22;
    this.turnRate = 3 / 60; this.thrustAccel = 400 / 60; this.maxSpeed = 300 / 60;
    this.detectRange = 4000; // 有电子舱
    this.ammo = 24; // 电磁炮24发
  }
  combatLogic() {
    super.combatLogic();
    let aimDiff = Math.abs(normAngle(angleTo(this, this.target) - this.angle));
    if (aimDiff < 0.15 && this.ammo > 0 && this.fireCooldown <= 0) {
      // 发射电磁炮 (直线高速)
      bullets.push(new Bullet(this.x, this.y, this.angle, this.isEnemy, 'railgun'));
      this.ammo--;
      this.fireCooldown = 120; // 2秒装填
    }
    // 导弹发射 (垂发,不用对准)
    if (this.fireCooldown <= 0) {
       bullets.push(new Bullet(this.x, this.y, this.angle + Math.PI/2, this.isEnemy, 'missile'));
       this.fireCooldown = 240;
    }
  }
  draw() {
    ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle);
    ctx.fillStyle = this.color;
    // 十字型 / 多支型主体
    ctx.fillRect(-20, -6, 40, 12); // 主干
    ctx.fillRect(-5, -18, 10, 36); // 侧翼
    // 电磁炮管x2
    ctx.fillStyle = '#fff'; ctx.fillRect(15, -8, 15, 3); ctx.fillRect(15, 5, 15, 3);
    ctx.restore();
    this.drawHealthBar();
    ctx.fillStyle = '#fff'; ctx.font = '10px Arial'; ctx.textAlign = 'center';
    ctx.fillText(`电磁弹:${this.ammo}`, this.x, this.y + 40);
  }
}

// 【导弹舰】: 多支型, 11舱, 垂直发射导弹, 2门近防炮
class MissileShip extends Ship {
  constructor(x, y, isEnemy) {
    super(x, y, isEnemy ? '#ff3366' : '#ffaa00', isEnemy);
    this.type = 'missile';
    this.radius = 30;
    this.turnRate = 1 / 60; this.thrustAccel = 1000 / 60; this.maxSpeed = 800 / 60;
    this.ammo = 80;
    this.fireCooldown = 0;
  }
  combatLogic() {
    // 导弹舰机动性极高,打完就跑
    if (this.ammo <= 0) {
      let fleeAng = angleTo(this.target, this);
      this.angle += Math.sign(normAngle(fleeAng - this.angle)) * this.turnRate;
      this.applyThrust();
      return;
    }
    super.combatLogic();
    if (this.fireCooldown <= 0 && dist(this, this.target) < 1000) {
      // 齐射 (这里简化为高频单发)
      for(let i=0; i<4; i++) {
         if(this.ammo > 0) {
             let spread = (Math.random()-0.5)*0.5;
             bullets.push(new Bullet(this.x, this.y, this.angle + spread, this.isEnemy, 'missile'));
             this.ammo--;
         }
      }
      this.fireCooldown = 80;
    }
  }
  draw() {
    ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle);
    ctx.fillStyle = this.color;
    // 多支型结构
    ctx.fillRect(-20, -10, 30, 20);
    ctx.fillRect(-10, -20, 20, 40); // 凸出的垂发单元
    // 垂发导弹口
    ctx.fillStyle = '#440000';
    ctx.fillRect(-5, -15, 6, 6); ctx.fillRect(-5, -5, 6, 6); ctx.fillRect(-5, 5, 6, 6);
    ctx.restore();
    this.drawHealthBar();
    ctx.fillStyle = '#fff'; ctx.font = '10px Arial'; ctx.textAlign = 'center';
    ctx.fillText(`导弹:${this.ammo}`, this.x, this.y + 40);
  }
}

// 【补给舰】: 专属AI逻辑,三接口,自动对接补给
class SupplyShip extends Ship {
  constructor(x, y, isEnemy) {
    super(x, y, '#44ff88', isEnemy);
    this.type = 'supply';
    this.radius = 18;
    this.turnRate = 4 / 60; this.thrustAccel = 400 / 60; this.maxSpeed = 200 / 60;
    this.state = 'seek'; // seek, dock, back
    this.targetFriend = null;
    this.hasResources = true; // 总资源量
  }
  update() {
    if (this.dead) return;
    if (this.fireCooldown > 0) this.fireCooldown--;
    
    // 补给舰特殊的寻路逻辑
    if (this.state === 'seek') {
      this.targetFriend = this.findNeedyFriend();
      if (this.targetFriend) {
        let tAng = angleTo(this, this.targetFriend);
        let diff = normAngle(tAng - this.angle);
        this.angle += Math.sign(diff) * Math.min(Math.abs(diff), this.turnRate);
        this.applyThrust();
        if (dist(this, this.targetFriend) < 40) this.state = 'dock';
      } else {
        // 没目标,游荡
        this.angle += (Math.random()-0.5)*0.1;
        this.applyThrust();
      }
    } else if (this.state === 'dock') {
      this.vx *= 0.8; this.vy *= 0.8;
      if (!this.targetFriend || this.targetFriend.dead) { this.state = 'seek'; return; }
      
      // 互相调整姿态对接
      let f = this.targetFriend;
      let tAng = angleTo(this, f);
      this.angle = normAngle(tAng + Math.PI); // 屁股对准人家
      f.angle = normAngle(tAng); // 对方脸对准自己
      
      // 开始补弹
      if (f.ammo < (f.type==='missile'?80:24)) {
        f.ammo += 0.2; 
        if (Math.random() < 0.2) particles.push({ x: this.x, y: this.y, vx: 0, vy: 0, life: 20, maxLife: 20, color: '#00ff00', size: 2 });
      } else {
        this.state = 'seek';
      }
    }
    this.x += this.vx; this.y += this.vy;
    if (this.x<30) this.x=30; if (this.x>W-30) this.x=W-30;
    if (this.y<30) this.y=30; if (this.y>H-30) this.y=H-30;
  }
  findNeedyFriend() {
    for (let e of entities) {
      if (!e.dead && e.isEnemy === this.isEnemy && e !== this) {
        if (e.ammo !== undefined && e.ammo < 10) return e; // 弹尽
      }
    }
    return null;
  }
  draw() {
    ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle);
    ctx.fillStyle = this.color;
    ctx.beginPath(); ctx.arc(0, 0, 15, 0, Math.PI*2); ctx.fill();
    // 三个对接接口
    ctx.fillStyle = '#fff';
    ctx.fillRect(13, -4, 5, 8); // 前
    ctx.fillRect(-3, -17, 6, 5); // 左
    ctx.fillRect(-3, 12, 6, 5); // 右
    // 状态灯
    ctx.fillStyle = this.state === 'dock' ? '#00ffff' : '#ff0000';
    ctx.beginPath(); ctx.arc(0, 0, 4, 0, Math.PI*2); ctx.fill();
    ctx.restore();
    this.drawHealthBar();
  }
}

// ==========================================
// 4. 弹药与粒子系统
// ==========================================
class Bullet {
  constructor(x, y, angle, isEnemy, type) {
    this.x = x; this.y = y; this.angle = angle;
    this.isEnemy = isEnemy; this.type = type;
    this.dead = false; this.life = 200;
    this.speed = 0; this.damage = 0;

    if (type === 'missile') { this.speed = 5; this.damage = 20; this.turnSpeed = 0.04; }
    else if (type === 'railgun') { this.speed = 15; this.damage = 40; }
    else if (type === 'heavy_laser') { this.speed = 25; this.damage = 3; }
    else if (type === 'pd_laser') { this.speed = 20; this.damage = 0; this.life = 30; } // 拦截弹
    
    this.vx = Math.cos(angle) * this.speed;
    this.vy = Math.sin(angle) * this.speed;
  }
  update() {
    if (this.dead) return;
    // 导弹追踪
    if (this.type === 'missile') {
      let target = entities.find(e => !e.dead && e.isEnemy !== this.isEnemy);
      if (target) {
        let tAng = angleTo(this, target);
        let cAng = Math.atan2(this.vy, this.vx);
        let diff = normAngle(tAng - cAng);
        cAng += Math.sign(diff) * this.turnSpeed;
        this.vx = Math.cos(cAng) * this.speed; this.vy = Math.sin(cAng) * this.speed;
        this.angle = cAng;
      }
    }

    this.x += this.vx; this.y += this.vy;
    this.life--;
    if (this.life <= 0 || this.x < 0 || this.x > W || this.y < 0 || this.y > H) this.dead = true;

    // 拦截逻辑
    if (this.type === 'pd_laser') {
      for(let b of bullets) {
        if(b.type === 'missile' && b.isEnemy !== this.isEnemy) {
          if(dist(this, b) < 20) { b.dead = true; this.dead = true; createExplode(b.x, b.y, '#66ccff'); return; }
        }
      }
    }

    // 命中舰船检测
    for (let e of entities) {
      if (!e.dead && e.isEnemy !== this.isEnemy) {
        if (dist(this, e) < e.radius) {
          if (e.hp !== undefined) e.hp -= this.damage;
          this.dead = true;
          createExplode(this.x, this.y, this.type==='missile'?'#ffaa00':'#ffffff');
          if (e.hp <= 0) { e.dead = true; createExplode(e.x, e.y, '#ff0000', 20); }
        }
      }
    }
  }
  draw() {
    if (this.dead) return;
    ctx.save(); ctx.translate(this.x, this.y); ctx.rotate(this.angle);
    if (this.type === 'missile') {
      ctx.fillStyle = '#ffaa00'; ctx.fillRect(-8, -2, 12, 4);
      ctx.fillStyle = 'rgba(255,0,0,0.5)'; ctx.fillRect(-12, -2, 4, 4);
    } else if (this.type === 'railgun') {
      ctx.fillStyle = '#00ffff'; ctx.fillRect(-15, -1, 30, 2);
    } else if (this.type === 'heavy_laser') {
      ctx.fillStyle = '#ffffff'; ctx.fillRect(-20, -1, 40, 2);
    } else {
      ctx.fillStyle = '#88ccff'; ctx.fillRect(-5, -1, 10, 2);
    }
    ctx.restore();
  }
}

function createExplode(x, y, color, count=5) {
  for (let i = 0; i < count; i++) {
    particles.push({
      x, y, vx: (Math.random()-0.5)*4, vy: (Math.random()-0.5)*4,
      life: 20 + Math.random()*10, maxLife: 30, color, size: Math.random()*2+1
    });
  }
}

// ==========================================
// 5. UI 控制与主循环
// ==========================================

// --- 战前配置系统 ---
const menuDiv = document.getElementById('menu');
const configContainer = document.getElementById('config-container');
let fleetConfig = { laser: 2, assault: 1, missile: 2, supply: 1 }; // 初始默认

function renderMenu() {
  configContainer.innerHTML = `
    <div class="config-row">
      <span class="name blue">激光舰 (线型)</span>
      <button class="btn" onclick="changeConfig('laser', -1)">-</button>
      <span id="num-laser">${fleetConfig.laser}</span>
      <button class="btn" onclick="changeConfig('laser', 1)">+</button>
    </div>
    <div class="config-row">
      <span class="name blue">突击舰 (十字型)</span>
      <button class="btn" onclick="changeConfig('assault', -1)">-</button>
      <span id="num-assault">${fleetConfig.assault}</span>
      <button class="btn" onclick="changeConfig('assault', 1)">+</button>
    </div>
    <div class="config-row">
      <span class="name red">导弹舰 (多支型)</span>
      <button class="btn" onclick="changeConfig('missile', -1)">-</button>
      <span id="num-missile">${fleetConfig.missile}</span>
      <button class="btn" onclick="changeConfig('missile', 1)">+</button>
    </div>
    <div class="config-row">
      <span class="name red">补给舰 (自动对接)</span>
      <button class="btn" onclick="changeConfig('supply', -1)">-</button>
      <span id="num-supply">${fleetConfig.supply}</span>
      <button class="btn" onclick="changeConfig('supply', 1)">+</button>
    </div>
  `;
}

window.changeConfig = (type, val) => {
  fleetConfig[type] = Math.max(0, Math.min(5, fleetConfig[type] + val));
  document.getElementById(`num-${type}`).innerText = fleetConfig[type];
};
renderMenu();

document.getElementById('startBtn').addEventListener('pointerdown', () => {
  menuDiv.style.display = 'none';
  startGame();
});

// --- 游戏引擎 ---
function startGame() {
  entities = []; bullets = []; particles = [];
  isGameRunning = true;

  // 生成蓝方 (左侧)
  for (let i = 0; i < fleetConfig.laser; i++) entities.push(new LaserShip(100 + Math.random()*50, H*0.2 + i*80, false));
  for (let i = 0; i < fleetConfig.assault; i++) entities.push(new AssaultShip(150 + Math.random()*50, H*0.6 + i*80, false));

  // 生成红方 (右侧)
  for (let i = 0; i < fleetConfig.missile; i++) entities.push(new MissileShip(W-100 - Math.random()*50, H*0.2 + i*80, true));
  for (let i = 0; i < fleetConfig.supply; i++) entities.push(new SupplyShip(W-200, H*0.5 + i*80, true));

  requestAnimationFrame(gameLoop);
}

function gameLoop() {
  if (!isGameRunning) return;

  // 背景拖影
  ctx.fillStyle = 'rgba(5, 9, 20, 0.4)';
  ctx.fillRect(0, 0, W, H);

  // 绘制星空
  ctx.fillStyle = '#fff';
  for(let i=0; i<20; i++) { ctx.globalAlpha = Math.random()*0.3; ctx.fillRect(Math.random()*W, Math.random()*H, 1, 1); }
  ctx.globalAlpha = 1;

  // 更新绘制实体
  for (let e of entities) { e.update(); if(!e.dead) e.draw(); }
  
  // 更新绘制子弹
  for (let i = bullets.length - 1; i >= 0; i--) {
    bullets[i].update();
    if (!bullets[i].dead) bullets[i].draw();
    else bullets.splice(i, 1);
  }

  // 更新绘制粒子
  for (let i = particles.length - 1; i >= 0; i--) {
    let p = particles[i];
    p.x += p.vx; p.y += p.vy; p.life--;
    ctx.globalAlpha = Math.max(0, p.life / p.maxLife);
    ctx.fillStyle = p.color;
    ctx.beginPath(); ctx.arc(p.x, p.y, p.size, 0, Math.PI*2); ctx.fill();
    if (p.life <= 0) particles.splice(i, 1);
  }
  ctx.globalAlpha = 1;

  // 胜负判定
  let blueAlive = entities.some(e => !e.isEnemy && !e.dead);
  let redAlive = entities.some(e => e.isEnemy && !e.dead);
  
  if (!blueAlive || !redAlive) {
    isGameRunning = false;
    ctx.fillStyle = 'rgba(0,0,0,0.8)'; ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = blueAlive ? '#66ccff' : '#ff3366';
    ctx.font = 'bold 32px Arial'; ctx.textAlign = 'center';
    ctx.fillText(blueAlive ? '蓝方舰队胜利' : (redAlive ? '红方舰队胜利' : '同归于尽'), W/2, H/2);
    ctx.fillStyle = '#fff'; ctx.font = '16px Arial';
    ctx.fillText('点击屏幕重新配置舰队', W/2, H/2 + 40);
    
    // 延迟一下再允许点击返回,防止误触
    setTimeout(() => {
      window.addEventListener('pointerdown', returnToMenu, { once: true });
    }, 1000);
  } else {
    requestAnimationFrame(gameLoop);
  }
}

function returnToMenu() {
  menuDiv.style.display = 'flex';
}
</script>
</body>
</html>

Game Source: 深空舰队 - 终极战术模拟

Creator: EpicCoder88

Libraries: none

Complexity: complex (624 lines, 21.5 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-epiccoder88-mvlx1tlk" to link back to the original. Then publish at arcadelab.ai/publish.