宇宙大战·救援地球
by FrostScout49516 lines17.7 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>宇宙大战·救援地球</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #000;
overflow: hidden;
font-family: Arial, sans-serif;
color: white;
text-align: center;
height: 100vh;
width: 100vw;
user-select: none;
}
#game {
position: relative;
width: 100%;
height: 100%;
}
canvas {
display: block;
background: linear-gradient(to bottom, #0a0a2e, #1a1a4e);
}
.ui {
position: absolute;
top: 10px;
left: 10px;
font-size: 18px;
text-shadow: 0 0 5px #0ff;
z-index: 10;
}
.health {
position: absolute;
top: 10px;
right: 10px;
font-size: 18px;
text-shadow: 0 0 5px #f00;
z-index: 10;
}
.level {
position: absolute;
top: 35px;
left: 10px;
font-size: 16px;
text-shadow: 0 0 5px #ff0;
z-index: 10;
}
.msg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 28px;
font-weight: bold;
text-shadow: 0 0 15px #fff;
display: none;
z-index: 20;
}
.hint {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
font-size: 14px;
color: #aaa;
z-index: 10;
}
</style>
</head>
<body>
<div id="game">
<canvas id="c"></canvas>
<div class="ui">能量: <span id="e">3</span></div>
<div class="health">护盾: <span id="h">100</span>%</div>
<div class="level">关卡: <span id="l">第1关 陨石带</span></div>
<div class="msg" id="m"></div>
<div class="hint">点左边=闪电号上移 | 点右边=堡垒号上移 | 点中间=发射</div>
</div>
<script>
const c = document.getElementById('c');
const ctx = c.getContext('2d');
c.width = window.innerWidth;
c.height = window.innerHeight;
// 游戏状态
let gameState = 'playing';
let level = 1;
let energy = 3;
let shield = 100;
let stars = [];
let meteors = [];
let enemies = [];
let bullets = [];
let cores = [];
let blackHole = null;
let time = 0;
// 玩家飞船
const player1 = { // 孩子:蓝色闪电号(左边屏幕控制)
x: c.width * 0.25,
y: c.height * 0.7,
width: 40,
height: 40,
color: '#0099ff'
};
const player2 = { // 大人:紫色堡垒号(右边屏幕控制)
x: c.width * 0.75,
y: c.height * 0.7,
width: 50,
height: 50,
color: '#9933ff'
};
// 点击控制(最简单的操作,绝对不会有问题)
document.addEventListener('click', (e) => {
if(gameState !== 'playing') return;
const x = e.clientX;
const midX = c.width / 2;
// 点左边:闪电号上移
if(x < midX - 50) {
player1.y = Math.max(0, player1.y - 30);
}
// 点右边:堡垒号上移
else if(x > midX + 50) {
player2.y = Math.max(0, player2.y - 30);
}
// 点中间:发射子弹
else {
bullets.push({
x: player1.x + player1.width / 2,
y: player1.y,
speed: 10,
color: player1.color
});
bullets.push({
x: player2.x + player2.width / 2,
y: player2.y,
speed: 9,
color: player2.color
});
}
});
// 初始化星星
function initStars() {
stars = [];
for(let i = 0; i < 100; i++) {
stars.push({
x: Math.random() * c.width,
y: Math.random() * c.height,
size: Math.random() * 2 + 1,
speed: Math.random() * 0.5 + 0.1
});
}
}
// 初始化关卡
function initLevel(n) {
meteors = [];
enemies = [];
bullets = [];
cores = [];
blackHole = null;
time = 0;
player1.x = c.width * 0.25;
player1.y = c.height * 0.7;
player2.x = c.width * 0.75;
player2.y = c.height * 0.7;
document.getElementById('l').textContent =
['第1关 陨石带', '第2关 太空战', '第3关 堡垒战', '第4关 黑洞战'][n-1];
showMsg('关卡 ' + n + ' 开始!', 1500);
if(n === 1) {
for(let i = 0; i < 10; i++) {
meteors.push({
x: Math.random() * c.width,
y: Math.random() * -500,
size: Math.random() * 30 + 20,
speed: Math.random() * 1.5 + 0.8
});
}
} else if(n === 2 || n === 3) {
for(let i = 0; i < 8; i++) {
enemies.push({
x: Math.random() * c.width,
y: Math.random() * -300,
width: 30,
height: 30,
speed: Math.random() * 1.2 + 0.5,
hp: n === 3 ? 3 : 2
});
}
} else if(n === 4) {
blackHole = {
x: c.width / 2,
y: c.height * 0.2,
radius: 80,
angle: 0,
active: true
};
for(let i = 0; i < 8; i++) {
const angle = (i / 8) * Math.PI * 2;
cores.push({
x: blackHole.x + Math.cos(angle) * 140,
y: blackHole.y + Math.sin(angle) * 140,
num: i + 1,
ok: false,
radius: 15
});
}
}
}
// 显示消息
function showMsg(text, duration) {
const el = document.getElementById('m');
el.textContent = text;
el.style.display = 'block';
setTimeout(() => { el.style.display = 'none'; }, duration);
}
// 更新游戏
function update() {
if(gameState !== 'playing') return;
time++;
// 更新星星
stars.forEach(star => {
star.y += star.speed;
if(star.y > c.height) {
star.y = 0;
star.x = Math.random() * c.width;
}
});
// 飞船自动下落
player1.y = Math.min(c.height - player1.height, player1.y + 1);
player2.y = Math.min(c.height - player2.height, player2.y + 1);
// 更新子弹
bullets = bullets.filter(bullet => {
bullet.y -= bullet.speed;
return bullet.y > 0;
});
// 关卡逻辑
if(level === 1) {
meteors.forEach((meteor, index) => {
meteor.y += meteor.speed;
if(meteor.y > c.height) {
meteor.y = Math.random() * -100;
meteor.x = Math.random() * c.width;
}
// 子弹打陨石
bullets.forEach((bullet, bIndex) => {
const dx = bullet.x - meteor.x;
const dy = bullet.y - meteor.y;
if(Math.sqrt(dx*dx + dy*dy) < meteor.size / 2) {
meteors.splice(index, 1);
bullets.splice(bIndex, 1);
}
});
// 撞飞船
if(collide(player1, meteor) || collide(player2, meteor)) {
shield -= 3;
updateUI();
meteors.splice(index, 1);
}
});
if(time > 600) nextLevel();
} else if(level === 2 || level === 3) {
enemies.forEach((enemy, index) => {
enemy.y += enemy.speed;
if(enemy.y > c.height) {
enemy.y = Math.random() * -100;
enemy.x = Math.random() * c.width;
}
// 子弹打敌人
bullets.forEach((bullet, bIndex) => {
if(bullet.x > enemy.x && bullet.x < enemy.x + enemy.width &&
bullet.y > enemy.y && bullet.y < enemy.y + enemy.height) {
enemy.hp--;
bullets.splice(bIndex, 1);
if(enemy.hp <= 0) enemies.splice(index, 1);
}
});
// 撞飞船
if(collide(player1, enemy) || collide(player2, enemy)) {
shield -= 5;
updateUI();
enemies.splice(index, 1);
}
});
if(enemies.length === 0 && time > 300) nextLevel();
} else if(level === 4) {
blackHole.angle += 0.02;
if(blackHole.active) {
// 护盾减少
if(time % 50 === 0) {
shield--;
updateUI();
}
}
// 破解星核(子弹碰到就破解)
cores.forEach((core, index) => {
if(!core.ok) {
bullets.forEach((bullet, bIndex) => {
const dx = bullet.x - core.x;
const dy = bullet.y - core.y;
if(Math.sqrt(dx*dx + dy*dy) < core.radius) {
bullets.splice(bIndex, 1);
const okNum = cores.filter(c => c.ok).length;
if(core.num === okNum + 1) {
core.ok = true;
showMsg('星核 ' + core.num + ' 破解成功!', 1000);
} else {
energy--;
updateUI();
showMsg('顺序错了!能量-1', 1000);
}
}
});
}
});
// 全部破解
if(cores.every(c => c.ok) && blackHole.active) {
blackHole.active = false;
showMsg('🎉 黑洞净化成功!', 2000);
setTimeout(() => {
gameState = 'win';
showMsg('🌍 地球得救了!恭喜通关!', 10000);
}, 2000);
}
}
// 游戏结束
if(shield <= 0 || energy <= 0) {
gameState = 'lose';
showMsg('游戏结束!刷新页面重新开始', 10000);
}
}
// 碰撞检测
function collide(obj1, obj2) {
return obj1.x < obj2.x + (obj2.width || obj2.size) &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y + (obj2.height || obj2.size) &&
obj1.y + obj1.height > obj2.y;
}
// 下一关
function nextLevel() {
level++;
if(level > 4) {
gameState = 'win';
showMsg('🌍 地球得救了!恭喜通关!', 10000);
} else {
showMsg('关卡完成!', 1500);
setTimeout(() => initLevel(level), 1500);
}
}
// 更新UI
function updateUI() {
document.getElementById('e').textContent = energy;
document.getElementById('h').textContent = shield;
}
// 绘制游戏
function draw() {
ctx.clearRect(0, 0, c.width, c.height);
// 画星星
stars.forEach(star => {
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fill();
});
// 画地球(第4关)
if(level === 4) {
ctx.fillStyle = '#00aaff';
ctx.beginPath();
ctx.arc(c.width / 2, c.height - 50, 40, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#00ff00';
ctx.beginPath();
ctx.arc(c.width / 2 - 10, c.height - 55, 15, 0, Math.PI * 2);
ctx.fill();
}
// 画陨石
meteors.forEach(meteor => {
ctx.fillStyle = '#888';
ctx.beginPath();
ctx.arc(meteor.x, meteor.y, meteor.size / 2, 0, Math.PI * 2);
ctx.fill();
});
// 画敌人
enemies.forEach(enemy => {
ctx.fillStyle = '#ff0000';
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
ctx.fillStyle = '#ffff00';
ctx.fillRect(enemy.x + 6, enemy.y + 6, 7, 7);
ctx.fillRect(enemy.x + enemy.width - 13, enemy.y + 6, 7, 7);
});
// 画子弹
bullets.forEach(bullet => {
ctx.fillStyle = bullet.color;
ctx.shadowColor = bullet.color;
ctx.shadowBlur = 10;
ctx.fillRect(bullet.x - 2, bullet.y, 4, 10);
ctx.shadowBlur = 0;
});
// 画黑洞
if(blackHole) {
ctx.save();
ctx.translate(blackHole.x, blackHole.y);
ctx.rotate(blackHole.angle);
ctx.strokeStyle = blackHole.active ? '#ff0000' : '#00ffff';
ctx.lineWidth = 6;
ctx.shadowColor = blackHole.active ? '#ff0000' : '#00ffff';
ctx.shadowBlur = 25;
ctx.beginPath();
ctx.arc(0, 0, blackHole.radius, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(0, 0, blackHole.radius - 12, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.restore();
// 画星核
cores.forEach(core => {
ctx.fillStyle = core.ok ? '#00ff00' : '#ffff00';
ctx.shadowColor = core.ok ? '#00ff00' : '#ffff00';
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.arc(core.x, core.y, core.radius, 0, Math.PI * 2);
ctx.fill();
if(!core.ok) {
ctx.fillStyle = '#000';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(core.num, core.x, core.y);
}
ctx.shadowBlur = 0;
});
}
// 画玩家1(蓝色闪电号)
ctx.fillStyle = player1.color;
ctx.shadowColor = player1.color;
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.moveTo(player1.x + player1.width / 2, player1.y);
ctx.lineTo(player1.x, player1.y + player1.height);
ctx.lineTo(player1.x + player1.width, player1.y + player1.height);
ctx.closePath();
ctx.fill();
ctx.shadowBlur = 0;
// 画玩家2(紫色堡垒号)
ctx.fillStyle = player2.color;
ctx.shadowColor = player2.color;
ctx.shadowBlur = 15;
ctx.fillRect(player2.x, player2.y, player2.width, player2.height);
ctx.fillStyle = '#cc66ff';
ctx.fillRect(player2.x + 10, player2.y + 10, player2.width - 20, player2.height - 20);
ctx.shadowBlur = 0;
}
// 游戏循环
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
// 启动游戏
initStars();
initLevel(level);
updateUI();
loop();
</script>
</body>
</html>
Game Source: 宇宙大战·救援地球
Creator: FrostScout49
Libraries: none
Complexity: complex (516 lines, 17.7 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: -frostscout49-mq39a8wg" to link back to the original. Then publish at arcadelab.ai/publish.