深空军械库 - 模块化舱段
by EpicCoder88351 lines12.4 KB
<!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.