摸金行动(保险箱+鸟窝+撤离点)
by BraveCoder31159 lines4.8 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>摸金行动</title>
<style>
body{margin:0;overflow:hidden;background:#222;}
#gameCanvas{width:100vw;height:100vh;display:block;}
#tip{position:fixed;top:10px;left:10px;color:#fff;background:#0008;padding:8px 12px;border-radius:6px;font-size:14px;}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="tip">滑动移动 | 点击射击 | 双击搜刮/撤离 | 三击换地图</div>
<script>
// 简易3D摸金游戏(手机触屏版)
const canvas=document.getElementById("gameCanvas");
const ctx=canvas.getContext("2d");
let w=canvas.width=window.innerWidth;
let h=canvas.height=window.innerHeight;
window.addEventListener("resize",()=>{w=canvas.width=window.innerWidth;h=canvas.height=window.innerHeight;});
// 玩家
let p={x:200,y:200,a:0,spd:2};
// 地图(3张)
const maps=[
{
name:"古墓一层",
walls:[
{x:0,y:0,w:800,h:20},{x:0,y:580,w:800,h:20},
{x:0,y:0,w:20,h:600},{x:780,y:0,w:20,h:600},
{x:200,y:200,w:200,h:20},{x:400,y:200,w:20,h:200}
],
safes:[{x:150,y:150,looted:0}],
nests:[{x:600,y:150,looted:0}],
enemies:[{x:300,y:300,hp:2}],
exit:{x:700,y:500}
},
{
name:"古墓二层",
walls:[
{x:0,y:0,w:800,h:20},{x:0,y:580,w:800,h:20},
{x:0,y:0,w:20,h:600},{x:780,y:0,w:20,h:600},
{x:100,y:100,w:20,h:300},{x:500,y:200,w:200,h:20}
],
safes:[{x:200,y:400,looted:0}],
nests:[{x:650,y:400,looted:0}],
enemies:[{x:250,y:250,hp:2},{x:550,y:350,hp:2}],
exit:{x:700,y:100}
},
{
name:"密室",
walls:[
{x:0,y:0,w:800,h:20},{x:0,y:580,w:800,h:20},
{x:0,y:0,w:20,h:600},{x:780,y:0,w:20,h:600},
{x:300,y:150,w:20,h:300}
],
safes:[{x:100,y:500,looted:0}],
nests:[{x:600,y:200,looted:0}],
enemies:[{x:200,y:200,hp:3},{x:450,y:450,hp:3}],
exit:{x:700,y:500}
}
];
let mapIndex=0;
let map=maps[mapIndex];
// 触屏
let touchStartX=0,touchStartY=0;
let tapCount=0,tapTimer=null;
canvas.addEventListener("touchstart",e=>{
touchStartX=e.touches[0].clientX;
touchStartY=e.touches[0].clientY;
tapCount++;
if(tapTimer)clearTimeout(tapTimer);
tapTimer=setTimeout(()=>{
if(tapCount===2)doubleTap();
if(tapCount===3)changeMap();
tapCount=0;
},300);
});
canvas.addEventListener("touchmove",e=>{
let dx=e.touches[0].clientX-touchStartX;
let dy=e.touches[0].clientY-touchStartY;
if(Math.abs(dx)>30)p.a+=dx*0.005;
if(Math.abs(dy)>30){
let nx=p.x+Math.cos(p.a)*dy*0.02;
let ny=p.y+Math.sin(p.a)*dy*0.02;
if(!hitWall(nx,ny)){p.x=nx;p.y=ny;}
}
touchStartX=e.touches[0].clientX;
touchStartY=e.touches[0].clientY;
});
canvas.addEventListener("touchend",e=>shoot());
function hitWall(x,y){
for(let w of map.walls)
if(x>w.x&&x<w.x+w.w&&y>w.y&&y<w.y+w.h)return 1;
return 0;
}
function dist(a,b){return Math.hypot(a.x-b.x,a.y-b.y);}
function shoot(){
for(let i=map.enemies.length-1;i>=0;i--){
let e=map.enemies[i];
if(dist(p,e)<150){
e.hp--;
if(e.hp<=0)map.enemies.splice(i,1);
}
}
}
function doubleTap(){
for(let s of map.safes)if(!s.looted&&dist(p,s)<50){s.looted=1;alert("开了保险箱!");return;}
for(let n of map.nests)if(!n.looted&&dist(p,n)<50){n.looted=1;alert("掏了鸟窝!");return;}
if(dist(p,map.exit)<50)alert("撤离成功!");
}
function changeMap(){
mapIndex=(mapIndex+1)%maps.length;
map=maps[mapIndex];
p.x=200;p.y=200;
alert("切换地图:"+map.name);
}
function update(){
for(let e of map.enemies){
let a=Math.atan2(p.y-e.y,p.x-e.x);
let nx=e.x+Math.cos(a)*1.2;
let ny=e.y+Math.sin(a)*1.2;
if(!hitWall(nx,ny)){e.x=nx;e.y=ny;}
if(dist(p,e)<30)alert("被怪抓了!");
}
}
function render(){
ctx.fillStyle="#333";ctx.fillRect(0,0,w,h);
// 墙
ctx.fillStyle="#555";
for(let w of map.walls)ctx.fillRect(w.x,w.y,w.w,w.h);
// 保险箱
ctx.fillStyle="#ffd700";
for(let s of map.safes){ctx.fillRect(s.x-15,s.y-15,30,30);ctx.fillStyle="#000";ctx.fillText(s.looted?"空":"锁",s.x-5,s.y+5);ctx.fillStyle="#ffd700";}
// 鸟窝
ctx.fillStyle="#8b4513";
for(let n of map.nests){ctx.beginPath();ctx.arc(n.x,n.y,20,0,Math.PI*2);ctx.fill();ctx.fillStyle="#fff";ctx.fillText(n.looted?"空":"窝",n.x-5,n.y+5);ctx.fillStyle="#8b4513";}
// 撤离点
ctx.fillStyle="#0f0";
ctx.fillRect(map.exit.x-20,map.exit.y-20,40,40);
// 敌人
ctx.fillStyle="#f00";
for(let e of map.enemies){ctx.beginPath();ctx.arc(e.x,e.y,15,0,Math.PI*2);ctx.fill();}
// 玩家
ctx.fillStyle="#00f";
ctx.beginPath();ctx.arc(p.x,p.y,20,0,Math.PI*2);ctx.fill();
ctx.strokeStyle="#0ff";ctx.lineWidth=2;
ctx.beginPath();ctx.moveTo(p.x,p.y);ctx.lineTo(p.x+Math.cos(p.a)*30,p.y+Math.sin(p.a)*30);ctx.stroke();
}
function loop(){update();render();requestAnimationFrame(loop);}
loop();
</script>
</body>
</html>
Game Source: 摸金行动(保险箱+鸟窝+撤离点)
Creator: BraveCoder31
Libraries: none
Complexity: moderate (159 lines, 4.8 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-bravecoder31-mqd5iip0" to link back to the original. Then publish at arcadelab.ai/publish.