🎮ArcadeLab

深空军械库 - 模块化舱段

by EpicCoder88
351 lines12.4 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: #03050a; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
  canvas { display: block; width: 100vw; height: 100vh; }
  .title { position: absolute; top: 20px; width: 100%; text-align: center; color: #66ccff; font-size: 20px; letter-spacing: 5px; text-shadow: 0 0 10px #66ccff; pointer-events: none; }
</style>
</head>
<body>
<div class="title">深空军械库 - 舱段拼接模块</div>
<canvas id="gameCanvas"></canvas>

<script>
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();

// 发光工具
function drawGlowCircle(x, y, r, color) {
  const g = ctx.createRadialGradient(x, y, 0, x, y, r);
  g.addColorStop(0, color);
  g.addColorStop(1, 'transparent');
  ctx.fillStyle = g;
  ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2); ctx.fill();
}

// ================= 战舰建模类 =================
// 基础单位:1个模块长度 = 20px。
// 画法原则:由尾部向头部画,用清晰的矩形+装甲接缝体现模块化。

class LaserShipModel {
  static draw(ctx, time) {
    const pulse = Math.sin(time * 0.005) * 0.5 + 0.5;
    
    // 0. 引擎尾焰 (动力舱后方)
    const engineFlame = ctx.createLinearGradient(-80, 0, -120 - pulse*20, 0);
    engineFlame.addColorStop(0, 'rgba(102, 204, 255, 0.8)');
    engineFlame.addColorStop(1, 'rgba(0, 102, 255, 0)');
    ctx.fillStyle = engineFlame;
    ctx.beginPath(); ctx.moveTo(-80, -10); ctx.lineTo(-130 - pulse*15, 0); ctx.lineTo(-80, 10); ctx.fill();

    // 1. 太阳能板 (挂载在生活舱两侧)
    ctx.fillStyle = '#1a2b4c';
    ctx.strokeStyle = '#3a5a8a'; ctx.lineWidth = 1;
    // 上翼
    ctx.fillRect(-40, -30, 30, 12); ctx.strokeRect(-40, -30, 30, 12);
    // 下翼
    ctx.fillRect(-40, 18, 30, 12); ctx.strokeRect(-40, 18, 30, 12);
    // 电池网格
    ctx.strokeStyle = 'rgba(102, 204, 255, 0.3)';
    for(let i=0; i<30; i+=6) {
      ctx.beginPath(); ctx.moveTo(-40+i, -30); ctx.lineTo(-40+i, -18); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(-40+i, 18); ctx.lineTo(-40+i, 30); ctx.stroke();
    }

    // 2. 拼接舱段 (线型:动力->生活->核心->武器)
    // 【舱段1:动力舱】
    ctx.fillStyle = '#2a3b5a'; ctx.fillRect(-70, -12, 20, 24);
    ctx.fillStyle = '#4a6b9a'; ctx.fillRect(-70, -12, 20, 6); // 受光面
    ctx.fillStyle = '#111'; ctx.fillRect(-75, -6, 5, 12); // 推进器喷口
    
    // 【拼接缝 1】 (装甲接缝)
    ctx.fillStyle = '#0a0f1a'; ctx.fillRect(-50, -14, 2, 28);

    // 【舱段2:生活舱】
    ctx.fillStyle = '#3e5a7a'; ctx.fillRect(-48, -10, 30, 20);
    ctx.fillStyle = '#6080a0'; ctx.fillRect(-48, -10, 30, 5); // 受光面
    // 生活舱舷窗 (一排发光小点)
    ctx.fillStyle = '#fff';
    for(let i=0; i<5; i++) {
      ctx.fillRect(-45 + i*6, -4, 2, 2);
    }

    // 【拼接缝 2】
    ctx.fillStyle = '#0a0f1a'; ctx.fillRect(-18, -12, 2, 24);

    // 【舱段3:核心舱】 (最宽的一截)
    ctx.fillStyle = '#6b7c99'; ctx.fillRect(-16, -14, 25, 28);
    ctx.fillStyle = '#9aaccc'; ctx.fillRect(-16, -14, 25, 8); // 受光面
    // 核心舱雷达/天线
    ctx.strokeStyle = '#66ccff'; ctx.lineWidth = 1;
    ctx.beginPath(); ctx.moveTo(-5, -14); ctx.lineTo(-5, -20); ctx.stroke();
    drawGlowCircle(-5, -20, 4, 'rgba(102, 204, 255, 0.8)');

    // 【拼接缝 3】
    ctx.fillStyle = '#0a0f1a'; ctx.fillRect(9, -10, 2, 20);

    // 【舱段4:武器舱 + 舰首】
    ctx.fillStyle = '#2a3b5a'; 
    ctx.beginPath();
    ctx.moveTo(11, -10);
    ctx.lineTo(45, -5); // 锥形收缩
    ctx.lineTo(55, 0);  // 舰首
    ctx.lineTo(45, 5);
    ctx.lineTo(11, 10);
    ctx.closePath(); ctx.fill();
    ctx.fillStyle = '#4a6b9a'; ctx.fillRect(11, -10, 30, 4);

    // 大功率激光主炮
    ctx.fillStyle = '#111'; ctx.fillRect(30, -2, 30, 4);
    // 充能发光
    drawGlowCircle(60, 0, 8, `rgba(102, 204, 255, ${0.4 + pulse*0.6})`);
  }
}

class AssaultShipModel {
  static draw(ctx, time) {
    const pulse = Math.sin(time * 0.01) * 0.5 + 0.5;
    
    // 尾焰
    const engineFlame = ctx.createLinearGradient(-60, 0, -100 - pulse*15, 0);
    engineFlame.addColorStop(0, 'rgba(0, 255, 204, 0.8)');
    engineFlame.addColorStop(1, 'rgba(0, 150, 150, 0)');
    ctx.fillStyle = engineFlame;
    ctx.fillRect(-100 - pulse*10, -8, 40 + pulse*10, 16);

    // 【主干舱段:动力->核心->武器】
    // 动力
    ctx.fillStyle = '#1e3d3d'; ctx.fillRect(-50, -12, 20, 24);
    ctx.fillStyle = '#111'; ctx.fillRect(-55, -6, 5, 12);
    // 核心
    ctx.fillStyle = '#336666'; ctx.fillRect(-30, -14, 40, 28);
    ctx.fillStyle = '#4a8c8c'; ctx.fillRect(-30, -14, 40, 6); // 受光
    
    // 【十字翼 / 侧向拼接舱段 (电子舱/辅助武器)】
    // 上方翼
    ctx.fillStyle = '#1e3d3d'; ctx.fillRect(-10, -40, 20, 26);
    ctx.strokeStyle = '#0a1a1a'; ctx.lineWidth = 2;
    ctx.strokeRect(-10, -40, 20, 26); // 边缘接缝
    // 下方翼
    ctx.fillStyle = '#1e3d3d'; ctx.fillRect(-10, 14, 20, 26);
    ctx.strokeRect(-10, 14, 20, 26);

    // 电子舱雷达阵列 (上方)
    ctx.fillStyle = '#00ffcc'; ctx.fillRect(-6, -42, 12, 3);
    ctx.save();
    ctx.translate(0, -40);
    ctx.rotate(time * 0.003);
    ctx.strokeStyle = '#fff'; ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(15, -5); ctx.stroke();
    ctx.restore();

    // 【前部突击武器舱 (电磁轨道炮)】
    ctx.fillStyle = '#2a5a5a'; ctx.fillRect(10, -10, 25, 20);
    // 轨道炮
    ctx.fillStyle = '#111'; 
    ctx.fillRect(35, -12, 25, 4); // 上轨道
    ctx.fillRect(35, 8, 25, 4);   // 下轨道
    // 电磁充能 (轨道中间的蓝光)
    ctx.fillStyle = `rgba(0, 255, 204, ${0.3 + pulse*0.7})`;
    ctx.fillRect(35, -4, 25, 8);
    
    // 舰首装甲
    ctx.fillStyle = '#4a8c8c';
    ctx.beginPath(); ctx.moveTo(60, -4); ctx.lineTo(65, 0); ctx.lineTo(60, 4); ctx.fill();

    // 近防炮
    ctx.fillStyle = '#888'; ctx.beginPath(); ctx.arc(15, -20, 3, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(15, 20, 3, 0, Math.PI*2); ctx.fill();
  }
}

class MissileShipModel {
  static draw(ctx, time) {
    const pulse = Math.sin(time * 0.008) * 0.5 + 0.5;
    
    // 尾焰
    const engineFlame = ctx.createLinearGradient(-70, 0, -110 - pulse*10, 0);
    engineFlame.addColorStop(0, 'rgba(255, 51, 102, 0.8)');
    engineFlame.addColorStop(1, 'rgba(255, 0, 0, 0)');
    ctx.fillStyle = engineFlame;
    ctx.fillRect(-110 - pulse*10, -12, 40 + pulse*10, 24);

    // 【主干:多节拼接舱段】
    ctx.fillStyle = '#4a1a1a'; ctx.fillRect(-60, -14, 90, 28); // 超长主干
    ctx.fillStyle = '#7a2a2a'; ctx.fillRect(-60, -14, 90, 6); // 整体受光面
    
    // 划分模块接缝
    ctx.fillStyle = '#111';
    for(let i=0; i<4; i++) ctx.fillRect(-40 + i*20, -14, 2, 28);

    // 【上层挂载模块:重发单元 (长方形盒子)】
    // 尾部动力模块上方
    ctx.fillStyle = '#2a0a0a'; ctx.fillRect(-55, -26, 20, 12);
    ctx.strokeStyle = '#551111'; ctx.strokeRect(-55, -26, 20, 12);
    // 核心区上方:大型导弹舱
    ctx.fillStyle = '#2a0a0a'; ctx.fillRect(-20, -30, 40, 16);
    ctx.strokeRect(-20, -30, 40, 16);
    
    // 画出导弹发射管
    for(let i=0; i<4; i++) {
      ctx.fillStyle = '#000'; ctx.fillRect(-15 + i*10, -28, 6, 12);
      // 发射管内部红光
      ctx.fillStyle = `rgba(255, 50, 50, ${0.2 + pulse*0.4})`;
      ctx.fillRect(-14 + i*10, -26, 4, 8);
    }

    // 【下层挂载模块:生活/电子舱 (稍微短一点)】
    ctx.fillStyle = '#3a1010'; ctx.fillRect(-30, 14, 50, 12);
    ctx.strokeStyle = '#551111'; ctx.strokeRect(-30, 14, 50, 12);
    
    // 【前部武器舱】
    ctx.fillStyle = '#5a2020'; 
    ctx.beginPath();
    ctx.moveTo(30, -14); ctx.lineTo(50, -8); ctx.lineTo(60, 0);
    ctx.lineTo(50, 8); ctx.lineTo(30, 14); ctx.closePath(); ctx.fill();

    // 前端近防炮
    ctx.fillStyle = '#888'; 
    ctx.beginPath(); ctx.arc(45, -6, 3, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(45, 6, 3, 0, Math.PI*2); ctx.fill();
  }
}

class SupplyShipModel {
  static draw(ctx, time) {
    const pulse = Math.sin(time * 0.006) * 0.5 + 0.5;
    
    // 尾焰
    const engineFlame = ctx.createLinearGradient(-60, 0, -90 - pulse*10, 0);
    engineFlame.addColorStop(0, 'rgba(255, 170, 0, 0.8)');
    engineFlame.addColorStop(1, 'rgba(255, 100, 0, 0)');
    ctx.fillStyle = engineFlame;
    ctx.beginPath(); ctx.moveTo(-60, -8); ctx.lineTo(-95 - pulse*10, 0); ctx.lineTo(-60, 8); ctx.fill();

    // 【主体结构:重型货舱模块拼装】
    // 1. 尾部动力/推进舱
    ctx.fillStyle = '#4a3a1a'; ctx.fillRect(-55, -12, 15, 24);
    ctx.fillStyle = '#111'; ctx.fillRect(-60, -6, 5, 12);

    // 2. 核心货舱模块 (很长)
    ctx.fillStyle = '#6b552a'; ctx.fillRect(-40, -18, 60, 36);
    ctx.fillStyle = '#8c703b'; ctx.fillRect(-40, -18, 60, 8); // 受光
    
    // 货舱模块拼接线
    ctx.fillStyle = '#221a0a'; 
    ctx.fillRect(-20, -18, 2, 36);
    ctx.fillRect(0, -18, 2, 36);

    // 货舱表面的十字标识 (代表补给)
    ctx.strokeStyle = '#fff'; ctx.lineWidth = 2;
    ctx.beginPath(); ctx.moveTo(-10, -6); ctx.lineTo(-10, 6); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(-16, 0); ctx.lineTo(-4, 0); ctx.stroke();

    // 3. 前部对接控制舱
    ctx.fillStyle = '#8c703b'; ctx.fillRect(20, -10, 20, 20);
    
    // 【外放对接接口 (圆柱形凸起)】
    // 前接口
    ctx.fillStyle = '#ccc'; ctx.fillRect(40, -6, 12, 12);
    ctx.strokeStyle = `rgba(0, 255, 0, ${0.5 + pulse*0.5})`; ctx.lineWidth = 2;
    ctx.strokeRect(40, -6, 12, 12); // 绿色对接光环

    // 上接口
    ctx.fillStyle = '#ccc'; ctx.fillRect(0, -26, 10, 8);
    ctx.strokeStyle = `rgba(0, 255, 0, ${0.5 + pulse*0.5})`;
    ctx.strokeRect(0, -26, 10, 8);

    // 下接口
    ctx.fillStyle = '#ccc'; ctx.fillRect(0, 18, 10, 8);
    ctx.strokeRect(0, 18, 10, 8);

    // 旋转警示灯
    ctx.save();
    ctx.translate(-30, 0);
    ctx.rotate(time * 0.004);
    ctx.fillStyle = '#ffaa00';
    ctx.beginPath(); ctx.arc(0, -12, 3, 0, Math.PI*2); ctx.fill();
    ctx.restore();
  }
}

// ================= 渲染主循环 =================
function render() {
  ctx.clearRect(0, 0, W, H);
  
  // 宇宙背景
  ctx.fillStyle = '#03050a';
  ctx.fillRect(0, 0, W, H);
  for(let i=0; i<60; i++) {
    let sx = (Math.sin cols(i * ;
123) * 0.  const5 + 0.5) * W;
 cell    let sy = (Math.cos(i * 456) * 0.5 + 0H.5) * H;
    let alpha = Math.sin(Date.now() * 0.001 + i) * 0.5 + 0.5;
    ctx.fillStyle = `rgba(255,255,255,${alpha * 0.4})`;
    ctx.fillRect(sx, sy, 1.5, 1.5);
  }

  const time = Date.now();
  const isPortrait = H > W;
  const cols = isPortrait ? 1 : 2;
  const rows = isPortrait ? 4 : 2;
  
  const cellW = W / = H / rows;
  
  // 缩放:因为舰体拉长了,所以缩放比例要调小一点以适应屏幕
  const scale = Math.min(cellW, cellH) / 200; 

  const ships = [
    { draw: LaserShipModel.draw, name: '线型 - 激光舰 (4舱段)', color: '#66ccff' },
    { draw: AssaultShipModel.draw, name: '十字型 - 突击舰 (侧翼拼接)', color: '#00ffcc' },
    { draw: MissileShipModel.draw, name: '多支型 - 导弹舰 (重发挂载)', color: '#ff3366' },
    { draw: SupplyShipModel.draw, name: '货舱型 - 补给舰 (多接口)', color: '#ffaa00' }
  ];

  ships.forEach((ship, index) => {
    const col = index % cols;
    const row = Math.floor(index / cols);
    
    const cx = cellW * col + cellW / 2;
    const cy = cellH * row + cellH / 2 - 20;

    ctx.save();
    ctx.translate(cx, cy);
    ctx.scale(scale, scale);
    
    // 绘制全息底盘
    ctx.strokeStyle = 'rgba(100, 150, 255, 0.1)';
    ctx.lineWidth = 2 / scale;
    ctx.beginPath(); ctx.arc(0, 0, 70, 0, Math.PI*2); ctx.stroke();
    ctx.beginPath(); ctx.arc(0, 0, 90, 0, Math.PI*2); ctx.stroke();
    
    ship.draw(ctx, time);
    ctx.restore();

    // 文字标签
    ctx.fillStyle = ship.color;
    ctx.font = `bold ${Math.min(16, cellW*0.04)}px sans-serif`;
    ctx.textAlign = 'center';
    ctx.shadowColor = ship.color;
    ctx.shadowBlur = 10;
    ctx.fillText(ship.name, cx, cy + 60);
    ctx.shadowBlur = 0;
  });

  requestAnimationFrame(render);
}

render();
</script>
</body>
</html>

Game Source: 深空军械库 - 模块化舱段

Creator: EpicCoder88

Libraries: none

Complexity: complex (351 lines, 12.4 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-mvn7aass" to link back to the original. Then publish at arcadelab.ai/publish.