🎮ArcadeLab

Pacman Stick

by DriftHawk95
275 lines6.2 KB
▶ Play

<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pacman Stick</title>
<style>
*{box-sizing:border-box}
body{
 margin:0;background:#080d24;color:white;
 font-family:Arial,sans-serif;
 display:flex;flex-direction:column;
 align-items:center;gap:12px;padding:15px;
}
.arena{
 background:radial-gradient(circle,#18265b,#080d24);
 border:2px solid #6575ff;border-radius:18px;
 padding:9px;width:100%;max-width:400px;
}
canvas{width:100%;height:auto;display:block;border-radius:12px}
.stick{
 width:142px;height:142px;border-radius:50%;
 background:radial-gradient(circle,#293b77,#101936);
 border:3px solid #738cff;
 box-shadow:inset 0 0 20px #0009,0 0 20px #536dff66;
 position:relative;touch-action:none;
}
.knob{
 position:absolute;width:58px;height:58px;
 border-radius:50%;left:39px;top:39px;
 background:radial-gradient(circle at 35% 30%,#c9d6ff,#526cff 65%,#2635a0);
 border:2px solid #dbe2ff;
 box-shadow:0 4px 12px #0009;
}
button{
 background:#5747d9;color:white;border:0;
 padding:12px 25px;border-radius:12px;
 font-size:17px;font-weight:bold;
}
</style>
</head>
<body>

<h2>🎮 Pacman Stick</h2>

<div class="arena">
 <div style="display:flex;justify-content:space-between;margin-bottom:10px">
  <span>⭐ امتیاز: <b id="sc">0</b></span>
  <span>❤️ جان: <b id="lv">3</b></span>
 </div>
 <canvas id="game" width="360" height="420"></canvas>
 <div id="status" style="text-align:center;font-size:13px;margin-top:10px">
 برای شروع، شروع بازی را بزن
 </div>
</div>

<button id="go">▶ شروع بازی</button>

<div>جوی‌استیک لمسی</div>
<div class="stick" id="stick">
 <div class="knob" id="knob"></div>
</div>
<div style="font-size:12px">دایره وسط را بگیر و در جهت دلخواه بکش</div>

<script>
const c=document.getElementById('game');
const ctx=c.getContext('2d');
const stick=document.getElementById('stick');
const knob=document.getElementById('knob');

const cell=30;
const map=[
"############",
"#..........#",
"#.##.##.##.#",
"#..........#",
"#.##.#.##..#",
"#....#.....#",
"###.###.##.#",
"#..........#",
"#.##.##.##.#",
"#..........#",
"#.##.##.##.#",
"#..........#",
"#..........#",
"############"
];

let walls=new Set(),dots=[];
let px=1,py=1,dx=0,dy=0;
let score=0,lives=3,ghosts=[];
let active=false,frame=0,timer=null,power=0;

function reset(){
 walls.clear();dots=[];
 map.forEach((s,y)=>[...s].forEach((v,x)=>{
  if(v==='#')walls.add(x+','+y);
  else dots.push({x,y});
 }));
 px=1;py=1;dx=dy=0;
 score=0;lives=3;power=0;
 ghosts=[
  {x:10,y:1,col:'#ff4d83'},
  {x:10,y:12,col:'#54eaff'},
  {x:6,y:7,col:'#d86bff'}
 ];
 update();draw();
}

function wall(x,y){return walls.has(x+','+y)}

function update(){
 document.getElementById('sc').textContent=score;
 document.getElementById('lv').textContent=lives;
}

function draw(){
 ctx.fillStyle='#080e27';
 ctx.fillRect(0,0,360,420);

 walls.forEach(k=>{
  let [x,y]=k.split(',').map(Number);
  ctx.fillStyle='#172c70';
  ctx.fillRect(x*30+2,y*30+2,26,26);
  ctx.strokeStyle='#526fff';
  ctx.strokeRect(x*30+3,y*30+3,24,24);
 });

 ctx.fillStyle='#fff2a3';
 dots.forEach(d=>{
  ctx.beginPath();
  ctx.arc(d.x*30+15,d.y*30+15,3,0,7);
  ctx.fill();
 });

 ctx.fillStyle='#ffe65b';
 ctx.beginPath();
 ctx.arc(165,225,7+Math.sin(frame/3)*2,0,7);
 ctx.fill();

 ctx.fillStyle='#ffe23e';
 ctx.beginPath();
 let a=Math.atan2(dy,dx);
 let m=.25+Math.abs(Math.sin(frame/2))*.3;
 ctx.moveTo(px*30+15,py*30+15);
 ctx.arc(px*30+15,py*30+15,12,a+m,a+Math.PI*2-m);
 ctx.fill();

 ghosts.forEach(g=>{
  ctx.fillStyle=power?'#448cff':g.col;
  ctx.beginPath();
  ctx.arc(g.x*30+15,g.y*30+15,11,Math.PI,0);
  ctx.lineTo(g.x*30+26,g.y*30+27);
  ctx.lineTo(g.x*30+4,g.y*30+27);
  ctx.fill();

  ctx.fillStyle='white';
  ctx.beginPath();
  ctx.arc(g.x*30+11,g.y*30+13,3,0,7);
  ctx.arc(g.x*30+19,g.y*30+13,3,0,7);
  ctx.fill();
 });
}

function move(){
 if(!active)return;
 frame++;

 if(Math.abs(dx)+Math.abs(dy)>.2){
  let nx=px+(Math.abs(dx)>Math.abs(dy)?Math.sign(dx):0);
  let ny=py+(Math.abs(dy)>=Math.abs(dx)?Math.sign(dy):0);
  if(!wall(nx,ny)){px=nx;py=ny}
 }

 let i=dots.findIndex(d=>d.x===px&&d.y===py);
 if(i>=0){dots.splice(i,1);score+=10;update()}

 if(px===5&&py===7){power=25;score+=50;update()}

 if(frame%2===0){
  ghosts.forEach(g=>{
   let opts=[[1,0],[-1,0],[0,1],[0,-1]]
    .filter(v=>!wall(g.x+v[0],g.y+v[1]));

   if(opts.length){
    opts.sort((a,b)=>
     Math.abs(g.x+a[0]-px)+Math.abs(g.y+a[1]-py)-
     (Math.abs(g.x+b[0]-px)+Math.abs(g.y+b[1]-py))
    );
    let v=Math.random()<.7?opts[0]:
     opts[Math.floor(Math.random()*opts.length)];
    g.x+=v[0];g.y+=v[1];
   }
  });
 }

 if(power>0)power--;

 if(ghosts.some(g=>g.x===px&&g.y===py)){
  if(power>0){
   ghosts.forEach(g=>{g.x=10;g.y=1});
   score+=100;update();
  }else{
   lives--;update();
   if(lives<=0){
    active=false;
    document.getElementById('status').textContent=
     'بازی تمام شد! دوباره شروع کن.';
   }else{
    px=1;py=1;dx=dy=0;
    document.getElementById('status').textContent=
     'یک جان از دست دادی!';
   }
  }
 }

 if(!dots.length){
  active=false;
  document.getElementById('status').textContent=
   'برنده شدی! آفرین! 🎉';
 }
 draw();
}

function start(){
 reset();
 active=true;
 document.getElementById('status').textContent=
  'جوی‌استیک را بکش و حرکت کن!';
 if(timer)clearInterval(timer);
 timer=setInterval(move,220);
}

document.getElementById('go').addEventListener('click',start);

let held=false;

function position(e){
 let b=stick.getBoundingClientRect();
 let cx=b.left+b.width/2;
 let cy=b.top+b.height/2;
 let x=e.clientX-cx,y=e.clientY-cy;
 let lim=43,len=Math.hypot(x,y);

 if(len>lim){x=x/len*lim;y=y/len*lim}

 knob.style.transform=`translate(${x}px,${y}px)`;
 dx=x/43;dy=y/43;
}

function release(){
 held=false;
 knob.style.transform='translate(0,0)';
 dx=dy=0;
}

stick.addEventListener('pointerdown',e=>{
 held=true;
 stick.setPointerCapture(e.pointerId);
 position(e);
});

stick.addEventListener('pointermove',e=>{
 if(held)position(e);
});

stick.addEventListener('pointerup',release);
stick.addEventListener('pointercancel',release);

reset();
</script>
</body>
</html>

Game Source: Pacman Stick

Creator: DriftHawk95

Libraries: none

Complexity: complex (275 lines, 6.2 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: pacman-stick-drifthawk95" to link back to the original. Then publish at arcadelab.ai/publish.