太空战机
by ShadowRider50461 lines11.0 KB
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>太空战机</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-family:Arial}
body{background:#111;overflow:hidden;}
/* 开始界面 */
#startPage{
width:100vw;height:100vh;
background:#0a0a20;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
gap:25px;
}
#startBtn,#skinBtn{
padding:16px 40px;
font-size:22px;
border:none;
border-radius:10px;
background:#00aaff;
color:#fff;
font-weight:bold;
width:220px;
}
#skinBtn{
background:#6644ff;
}
/* 皮肤选择界面 */
#skinPage{
width:100vw;height:100vh;
background:#0a0a20;
display:none;
flex-direction:column;
align-items:center;
justify-content:center;
gap:30px;
}
.skin-item{
width:240px;
padding:15px;
border:2px solid #444;
border-radius:10px;
color:#fff;
text-align:center;
}
.skin-locked{
border-color:#ff5555;
color:#aaa;
}
#backBtn{
padding:12px 30px;
border:none;
border-radius:8px;
background:#555;
color:#fff;
font-size:18px;
}
/* 游戏主界面 */
#gamePage{
width:100vw;height:100vh;
display:none;
flex-direction:column;
align-items:center;
justify-content:space-around;
padding:15px 0;
position:relative;
}
#topInfo{
display:flex;
gap:40px;
}
#scoreBox,#hpBox{
color:#00aaff;
font-size:26px;
font-weight:bold;
}
#gameCanvas{
border:2px solid #333;
background:#000518;
}
/* 控制按钮区域 */
#controlArea{
display:flex;
align-items:center;
gap:40px;
}
#directionPad{
display:grid;
grid-template-columns: 60px 60px;
gap:6px;
}
#fireBtn{
width:80px;height:80px;
border:none;
border-radius:50%;
background:#ff3333;
color:#fff;
font-size:18px;
font-weight:bold;
}
#fireBtn:active{background:#ff6666;}
.dir-btn{
width:60px;height:60px;
font-size:24px;
border:none;
border-radius:8px;
background:#444;
color:#fff;
}
.dir-btn:active{background:#00aaff;}
#btnLeft{grid-column:1;}
#btnRight{grid-column:2;}
/* 失败弹窗 */
#failModal{
position:absolute;
top:0;left:0;
width:100%;height:100%;
background:rgba(0,0,0,0.85);
display:none;
flex-direction:column;
align-items:center;
justify-content:center;
gap:20px;
}
#failText{
color:#ff4444;
font-size:48px;font-weight:bold;
}
#finalScore{
color:#00aaff;
font-size:28px;
}
#restartBtn,#menuBtn{
padding:14px 36px;
font-size:20px;
border:none;
border-radius:8px;
color:#fff;
}
#restartBtn{
background:#00aaff;
}
#menuBtn{
background:#666666;
}
</style>
</head>
<body>
<!-- 主菜单 -->
<div id="startPage">
<h1 style="color:#00aaff;font-size:42px">太空战机</h1>
<button id="startBtn">开始游戏</button>
<button id="skinBtn">更换战机皮肤</button>
</div>
<!-- 皮肤选择页 -->
<div id="skinPage">
<h2 style="color:#fff">战机皮肤商店</h2>
<div class="skin-item" id="skin1">
<h3>纯白战机</h3>
<p>已解锁,直接使用</p>
</div>
<div class="skin-item skin-locked" id="skin2">
<h3>深蓝战机</h3>
<p>累计得分 ≥ 150 解锁</p>
</div>
<button id="backBtn">返回</button>
</div>
<!-- 游戏界面 -->
<div id="gamePage">
<div id="topInfo">
<div id="scoreBox">当前得分:0</div>
<div id="hpBox">生命值:❤❤❤</div>
</div>
<canvas id="gameCanvas" width="400" height="450"></canvas>
<div id="controlArea">
<div id="directionPad">
<button class="dir-btn" id="btnLeft">←</button>
<button class="dir-btn" id="btnRight">→</button>
</div>
<button id="fireBtn">发射</button>
</div>
<div id="failModal">
<div id="failText">战机被击毁</div>
<div id="finalScore"></div>
<button id="restartBtn">重新再来</button>
<button id="menuBtn">返回主菜单</button>
</div>
</div>
<script>
// 页面元素
const startPage = document.getElementById('startPage');
const skinPage = document.getElementById('skinPage');
const gamePage = document.getElementById('gamePage');
const startBtn = document.getElementById('startBtn');
const skinBtn = document.getElementById('skinBtn');
const backBtn = document.getElementById('backBtn');
const skin1 = document.getElementById('skin1');
const skin2 = document.getElementById('skin2');
const failModal = document.getElementById('failModal');
const restartBtn = document.getElementById('restartBtn');
const menuBtn = document.getElementById('menuBtn');
const scoreBox = document.getElementById('scoreBox');
const hpBox = document.getElementById('hpBox');
const finalScore = document.getElementById('finalScore');
const btnLeft = document.getElementById('btnLeft');
const btnRight = document.getElementById('btnRight');
const fireBtn = document.getElementById('fireBtn');
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// 全局存档数据(浏览器本地保存)
let saveData = JSON.parse(localStorage.getItem('spaceFighterSave')) || {
totalScore: 0,
useSkin: 1,
unlockSkin2: false
};
// 保存存档
function saveGame(){
localStorage.setItem('spaceFighterSave', JSON.stringify(saveData));
}
// 游戏变量
let score = 0;
let hp = 3;
let gameLoop;
let moveDir = 0;
let bullets = [];
let enemies = [];
let enemySpawnTimer;
// 玩家战机设置
const player = {
x: 175,
y: 380,
w: 50,
h: 40,
speed: 11
};
// 更新皮肤解锁状态
function updateSkinUI(){
if(saveData.unlockSkin2){
skin2.classList.remove('skin-locked');
skin2.innerHTML = `<h3>深蓝战机</h3><p>已解锁,点击使用</p>`;
}
}
// 选择皮肤
skin1.onclick = ()=>{
saveData.useSkin = 1;
saveGame();
alert("已切换为纯白战机");
};
skin2.onclick = ()=>{
if(saveData.unlockSkin2){
saveData.useSkin = 2;
saveGame();
alert("已切换为深蓝战机");
}else{
alert("累计得分达到150分才能解锁!");
}
};
// 页面切换
skinBtn.onclick = ()=>{
updateSkinUI();
startPage.style.display = 'none';
skinPage.style.display = 'flex';
};
backBtn.onclick = ()=>{
skinPage.style.display = 'none';
startPage.style.display = 'flex';
};
// 初始化游戏
function initGame(){
score = 0;
hp = 3;
moveDir = 0;
bullets = [];
enemies = [];
scoreBox.innerText = `当前得分:${score}`;
hpBox.innerText = `生命值:❤❤❤`;
player.x = 175;
if(gameLoop) clearInterval(gameLoop);
if(enemySpawnTimer) clearInterval(enemySpawnTimer);
gameLoop = setInterval(gameUpdate, 16);
enemySpawnTimer = setInterval(spawnEnemy, 1200);
}
// 生成敌人:限制左右边界,不会贴边
function spawnEnemy(){
const margin = 40;
const xPos = margin + Math.random() * (canvas.width - margin*2 - 20);
enemies.push({
x: xPos,
y: -20,
r: 12,
speed: 3.5
});
}
// 发射子弹
function fireBullet(){
bullets.push({
x: player.x + player.w / 2 - 3,
y: player.y,
w:6,
h:14,
speed:7
});
}
// 长按移动控制
btnLeft.addEventListener('mousedown', ()=>moveDir = -1);
btnLeft.addEventListener('mouseup', ()=>moveDir = 0);
btnLeft.addEventListener('mouseleave', ()=>moveDir = 0);
btnRight.addEventListener('mousedown', ()=>moveDir = 1);
btnRight.addEventListener('mouseup', ()=>moveDir = 0);
btnRight.addEventListener('mouseleave', ()=>moveDir = 0);
btnLeft.addEventListener('touchstart', (e)=>{e.preventDefault();moveDir = -1});
btnLeft.addEventListener('touchend', ()=>moveDir = 0);
btnRight.addEventListener('touchstart', (e)=>{e.preventDefault();moveDir = 1});
btnRight.addEventListener('touchend', ()=>moveDir = 0);
fireBtn.addEventListener('click', fireBullet);
fireBtn.addEventListener('touchstart', (e)=>{e.preventDefault();fireBullet()});
// 开始游戏
startBtn.onclick = ()=>{
startPage.style.display = 'none';
gamePage.style.display = 'flex';
initGame();
};
// 重新再来
restartBtn.onclick = ()=>{
failModal.style.display = 'none';
initGame();
};
// 返回主菜单
menuBtn.onclick = ()=>{
failModal.style.display = 'none';
gamePage.style.display = 'none';
startPage.style.display = 'flex';
clearInterval(gameLoop);
clearInterval(enemySpawnTimer);
};
// 扣血逻辑
function loseHp(){
hp--;
let heartStr = "";
for(let i=0;i<hp;i++) heartStr += "❤";
hpBox.innerText = `生命值:${heartStr}`;
if(hp <= 0){
clearInterval(gameLoop);
clearInterval(enemySpawnTimer);
// 累计总分更新,判断解锁皮肤
saveData.totalScore += score;
if(saveData.totalScore >= 150) saveData.unlockSkin2 = true;
saveGame();
finalScore.innerText = `最终得分:${score}`;
failModal.style.display = 'flex';
}
}
// 游戏主循环
function gameUpdate(){
ctx.fillStyle = '#000518';
ctx.fillRect(0,0,canvas.width,canvas.height);
player.x += moveDir * player.speed;
player.x = Math.max(0, Math.min(canvas.width - player.w, player.x));
// 更新子弹
for(let i = bullets.length - 1; i >= 0; i--){
bullets[i].y -= bullets[i].speed;
if(bullets[i].y < -20) bullets.splice(i,1);
}
// 敌人更新与碰撞
for(let ei = enemies.length - 1; ei >= 0; ei--){
const enemy = enemies[ei];
enemy.y += enemy.speed;
// 撞到战机扣血
const dx = (player.x+player.w/2) - enemy.x;
const dy = (player.y+player.h/2) - enemy.y;
const dist = Math.sqrt(dx*dx+dy*dy);
if(dist < enemy.r + 20){
enemies.splice(ei,1);
loseHp();
if(hp <= 0) return;
}
// 子弹击中敌人
for(let bi = bullets.length -1; bi >=0; bi--){
const bullet = bullets[bi];
if(bullet.x < enemy.x+enemy.r && bullet.x+bullet.w > enemy.x-enemy.r
&& bullet.y < enemy.y+enemy.r && bullet.y+bullet.h > enemy.y-enemy.r){
enemies.splice(ei,1);
bullets.splice(bi,1);
score += 15;
scoreBox.innerText = `当前得分:${score}`;
break;
}
}
if(enemy.y > canvas.height + 20) enemies.splice(ei,1);
}
// 绘制战机皮肤
if(saveData.useSkin === 1) ctx.fillStyle = '#ffffff';
else ctx.fillStyle = '#2244aa';
ctx.beginPath();
ctx.moveTo(player.x+player.w/2, player.y);
ctx.lineTo(player.x, player.y+player.h);
ctx.lineTo(player.x+player.w, player.y+player.h);
ctx.closePath();
ctx.fill();
// 子弹
ctx.fillStyle = '#00aaff';
bullets.forEach(b=>{
ctx.fillRect(b.x,b.y,b.w,b.h);
});
// 红色敌人球
ctx.fillStyle = '#ff2222';
enemies.forEach(e=>{
ctx.beginPath();
ctx.arc(e.x,e.y,e.r,0,Math.PI*2);
ctx.fill();
});
}
updateSkinUI();
</script>
</body>
</html>
Game Source: 太空战机
Creator: ShadowRider50
Libraries: none
Complexity: complex (461 lines, 11.0 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-shadowrider50" to link back to the original. Then publish at arcadelab.ai/publish.