🎮ArcadeLab

摸金行动(保险箱+鸟窝+撤离点)

by BraveCoder31
159 lines4.8 KB
▶ Play
<!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.