0

Hey I am currently building a simple pacman in javascript as a learning project. I am able to render a basic board, pacman, pellets and big pellets with basic canvas drawings (arc etc) . The game is responsive to key codes moving pacman around but Imstruggling when I want to test for collision and access x and y values of canvas drawings. My board is drawn in for loop that iterates through a layout/grid 2d array of numbers and draws something different depending on the number, 0 representing walls, 1 - pellets etc. I feel I may be making an error in the drawBoard for loop also.. I have started to go back and forth between using a function to draw walls and then trying to access its X and Y positions:

function drawBoard(){
  for (let i = 0; i < ROWS; i++){
    for (let j = 0; j < COLS; j++){
      const x = j * tile.width;
      const y = i * tile.height;
      if (layout[i][j] === 0){
        wallX = x;
        wallY = y;
        drawWall(wallX, wallY);
      // walls.push(new Wall(wallX, wallY));
    } else if (layout[i][j] === 1){
      drawPellets(x, y);
    } else if (layout[i][j] === 4){
      drawBigPellets(x,y);
    }
  };
};
}

function drawWall(wallX, wallY){
  ctx.fillStyle="lightBlue";
  ctx.fillRect(wallX, wallY, wallWidth , wallHeight);
  ctx.strokeRect(wallX, wallY, wallWidth, wallHeight); 
}

or creating new class objects in a for loop then attempting to access the x and y position:

class Wall {
  // constructor(x, y){
  //   this.x = x;
  //   this.y = y;
  //   this.wallWidth = wallWidth;
  //   this.wallHeight = wallHeight;
   
//     for (var w = 0; w<walls.length;w++){
//         walls[w].draw();
//         walls[w].checkCollision();
//         if (collided) {
//           console.log("collided");
//         }
//       };
    
//   }
//   draw(){
//     ctx.fillStyle="lightBlue";
//     ctx.fillRect(this.x, this.y, this.wallWidth , this.wallHeight);
//     ctx.strokeRect(this.x, this.y, this.wallWidth , this.wallHeight);
//   }
//   checkCollision(){
//     if (getDistance(this.x, this.y, GAME_STATE.playerX, GAME_STATE.playerY) < 0){
//       collided = true;
//     };
//   }
    
// }

To detect for collision I have tried two different functions, shown below, trying also to call them in a method of Wall object..

function intersectRect(r1, r2) {
  return !(r2.left > r1.right || 
           r2.right < r1.left || 
           r2.top > r1.bottom ||
           r2.bottom < r1.top);
}

// function getDistance(x1, y1, x2, y2){
//   var xDistance = x2 - x1;
//   var yDistance = y2 - y1;
  
//   return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
// }

Needless to say Im getting very confused and was wandering if someone could give me a simple way to detect whether pacman touches a drawn wall or pellet etc..

//notes:
// draw grid: pellets, ghost, pacman
// move pacman automatically and change direction
// add score
// life lost
// gameover
// reset when gameover
//TO DO:
//1. Create layout matrix - render matrix as grid with tile width and height.
//for each number in matrix draw a tile with width and height and value image or color. draw tiles.
//2. Give different value to corresponding number on grid e.g. color/img
//3. Draw players
//4. Give functions
const KEY_CODE_RIGHT = 39;
const KEY_CODE_LEFT = 37;
const KEY_CODE_UP = 38;
const KEY_CODE_DOWN = 40;
const COLS = 19;
const ROWS = 22;

const PLAYER_MAX_SPEED = 100;

const canvas = document.getElementById("pacmanBoard");
const ctx = canvas.getContext("2d");

let tile = {
  width: 25,
  height: 25
};
canvas.width = tile.width * 19;
canvas.height = tile.width * 22;
let wallX, wallY,
  wallWidth = tile.width;
let wallHeight = tile.height;

const GAME_STATE = {
  lastTime: Date.now(),
  leftPressed: false,
  rightPressed: false,
  upPressed: false,
  downPressed: false,
  playerX: canvas.width / 2,
  playerY: canvas.height / 2 - 10,
  playerRadius: 10,
  pellets: [],
  walls: []
}

const layout = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 4, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 4, 0],
  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0],
  [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
  [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
  [2, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 2],
  [0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0],
  [2, 2, 2, 2, 1, 1, 1, 0, 3, 3, 3, 0, 1, 1, 1, 2, 2, 2, 2],
  [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
  [2, 2, 2, 0, 1, 0, 1, 1, 1, 2, 1, 1, 1, 0, 1, 0, 2, 2, 2],
  [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
  [0, 4, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4, 0],
  [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
  [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
  [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
let walls = [];
let collided = false;

function draw() {

  clearCanvas();
  drawPlayer();
  drawBoard();
}

function clamp(v, min, max) {
  if (v < min) {
    return min;
  } else if (v > max) {
    return max;
  } else {
    return v;
  }
}

function clearCanvas() {
  ctx.fillStyle = "black";
  ctx.strokeStyle = "blue";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.strokeRect(0, 0, canvas.width, canvas.height);
}

function drawBoard() {
  for (let i = 0; i < ROWS; i++) {
    for (let j = 0; j < COLS; j++) {

      const x = j * tile.width;
      const y = i * tile.height;
      if (layout[i][j] === 0) {
        wallX = x;
        wallY = y;
        drawWall(wallX, wallY);
        // walls.push(new Wall(wallX, wallY));
      } else if (layout[i][j] === 1) {
        drawPellets(x, y);
      } else if (layout[i][j] === 4) {
        drawBigPellets(x, y);
      }

    };
  };

}

function drawWall(wallX, wallY) {
  ctx.fillStyle = "lightBlue";
  ctx.fillRect(wallX, wallY, wallWidth, wallHeight);
  ctx.strokeRect(wallX, wallY, wallWidth, wallHeight);
  //   class Wall {
  //   constructor(x, y){
  //     this.x = x;
  //     this.y = y;
  //     this.width = tile.width;
  //     this.height = tile.height;
  //     this.type = "wall";

  //   }
  //   draw(){
  //     ctx.fillStyle="lightBlue";
  //     ctx.fillRect(this.x, this.y, this.width , this.height);
  //     ctx.strokeRect(this.x, this.y, this.width , this.height);
  //   }
  //   checkCollision(){

  //     return (GAME_STATE.playerX-GAME_STATE.playerRadius < this.x + 20)
  //   && (GAME_STATE.playerX+GAME_STATE.playerRadius > this.x)
  //   && (GAME_STATE.playerY-GAME_STATE.playerRadius < this.y + 20)
  //   && (GAME_STATE.playerY+GAME_STATE.playerRadius > this.y)
  //   ;
  // }
  // }
}

// class Wall {
// constructor(x, y){
//   this.x = x;
//   this.y = y;
//   this.wallWidth = wallWidth;
//   this.wallHeight = wallHeight;

//     for (var w = 0; w<walls.length;w++){
//         walls[w].draw();
//         walls[w].checkCollision();
//         if (collided) {
//           console.log("collided");
//         }
//       };

//   }
//   draw(){
//     ctx.fillStyle="lightBlue";
//     ctx.fillRect(this.x, this.y, this.wallWidth , this.wallHeight);
//     ctx.strokeRect(this.x, this.y, this.wallWidth , this.wallHeight);
//   }
//   checkCollision(){
//     if (getDistance(this.x, this.y, GAME_STATE.playerX, GAME_STATE.playerY) < 0){
//       collided = true;
//     };
//   }

// }

// function getDistance(x1, y1, x2, y2){
//   var xDistance = x2 - x1;
//   var yDistance = y2 - y1;

//   return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
// }
function drawPellets(x, y) {
  ctx.beginPath();
  ctx.arc(x + tile.width / 2, y + tile.height / 2, 3, 0, 2 * Math.PI, false);
  ctx.fillStyle = "blue";
  ctx.fill();
  GAME_STATE.pellets.push();
}

function removePellets(x, y) {
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, tile.width, tile.height);
}

function drawBigPellets(x, y) {
  ctx.beginPath();
  ctx.arc(x + tile.width / 2, y + tile.height / 2, 5, 0, 2 * Math.PI, false);
  ctx.fillStyle = "green";
  ctx.fill();
}

function drawPlayer() {

  ctx.beginPath();
  ctx.arc(GAME_STATE.playerX, GAME_STATE.playerY, GAME_STATE.playerRadius, 0.25 * Math.PI, 1.25 * Math.PI, false);
  ctx.fillStyle = "rgb(255, 255, 0)";
  ctx.fill();
  ctx.beginPath();
  ctx.arc(GAME_STATE.playerX, GAME_STATE.playerY, GAME_STATE.playerRadius, 0.75 * Math.PI, 1.75 * Math.PI, false);
  ctx.fill();
}

function updatePlayer(dt) {
  if (GAME_STATE.leftPressed) {
    GAME_STATE.playerX -= dt * PLAYER_MAX_SPEED;
    // GAME_STATE.playerX -= dt * PLAYER_MAX_SPEED;
  }
  if (GAME_STATE.rightPressed) {
    GAME_STATE.playerX += dt * PLAYER_MAX_SPEED;
  }
  if (GAME_STATE.upPressed) {
    GAME_STATE.playerY -= dt * PLAYER_MAX_SPEED;
  }
  if (GAME_STATE.downPressed) {
    GAME_STATE.playerY += dt * PLAYER_MAX_SPEED;
  }

  drawPlayer(GAME_STATE.playerX, GAME_STATE.playerY);
  GAME_STATE.playerX = clamp(GAME_STATE.playerX, GAME_STATE.playerRadius, canvas.width - GAME_STATE.playerRadius);
  GAME_STATE.playerY = clamp(GAME_STATE.playerY, GAME_STATE.playerRadius, canvas.height - GAME_STATE.playerRadius);
}




function update(e) {

  const currentTime = Date.now();
  const dt = (currentTime - GAME_STATE.lastTime) / 1000.0;
  draw();
  updatePlayer(dt);
  // if (intersectRect(GAME_STATE.playerRadius, wallX)) {
  //   console.log("intersected");
  // }


  GAME_STATE.lastTime = currentTime;
  window.requestAnimationFrame(update);
}


function intersectRect(r1, r2) {
  return !(r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top);
}

function onKeyDown(e) {
  if (e.keyCode === KEY_CODE_LEFT) {
    GAME_STATE.leftPressed = true;
    // GAME_STATE.playerX -= 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_RIGHT) {
    GAME_STATE.rightPressed = true;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_UP) {
    GAME_STATE.upPressed = true;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_DOWN) {
    GAME_STATE.downPressed = true;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  }
}

function onKeyUp(e) {
  if (e.keyCode === KEY_CODE_LEFT) {
    GAME_STATE.leftPressed = false;
    // GAME_STATE.playerX -= 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_RIGHT) {
    GAME_STATE.rightPressed = false;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_UP) {
    GAME_STATE.upPressed = false;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  } else if (e.keyCode === KEY_CODE_DOWN) {
    GAME_STATE.downPressed = false;
    // GAME_STATE.playerX += 5;
    // const player = document.querySelector(".player");
    // setPosition(player, GAME_STATE.playerX, GAME_STATE.playerY);
  }
}

window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
window.requestAnimationFrame(update);




// let score = 0;
// let lives = 3;
// let tile = {
//   width: 20,
//   height: 20
// };
// board.width = tile.width * 19;
// board.height = tile.width * 22; 
// let pacmanPosition = {
//   x: board.width/2,
//   y: board.height/2
// };
// let dx = 10;
// let dy = 0;

// const maze = new Array();
// const mazeWidth = board.width;
// const mazeHeight = board.height;
//  // wall    = 0;
// // pellet = 1;
// // empty   = 2;
// // block   = 3;
// // bigpill  = 4;

// const layout = [
//   [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
//  [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
//  [0, 4, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 4, 0],
//  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
//  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
//  [0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0],
//  [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
//  [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
//  [2, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 2, 2, 2],
//  [0, 0, 0, 0, 1, 0, 1, 0, 0, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0],
//  [2, 2, 2, 2, 1, 1, 1, 0, 3, 3, 3, 0, 1, 1, 1, 2, 2, 2, 2],
//  [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
//  [2, 2, 2, 0, 1, 0, 1, 1, 1, 2, 1, 1, 1, 0, 1, 0, 2, 2, 2],
//  [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
//  [0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
//  [0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
//  [0, 4, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 4, 0],
//  [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
//  [0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
//  [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
//  [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
//  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// ];

// function makeMaze(){
//   for (var i = 0; i< layout.length; i++) {
//     maze[x] = new Array();
//     for (var j = 0; j < layout[i].length; j++){
//       if (maze[i][j] === 0){

//       }
//     }
//   }
// }

// function drawAll() {
//   for (var x=0;x<maze.length;x++){
//   for(var y=0;y<maze[x].length;y++){
//    drawTile(x,y);  }
//     }
// }

// function drawTile(x,y) {
//   ctx.fillStyle="lightBlue";
//   ctx.fillRect(x * tile.width , y * tile.height, tile.width , tile.height);
//   ctx.strokeRect(x * tile.width , y * tile.height, tile.width , tile.height); 
// }

// main();

// function main() {
//   clearCanvas();
//   drawPacman();
//   drawPellets();
//   drawGhosts();
//   // drawAll();
// }

// function reset() {

// }

// function clearCanvas(){
//   ctx.fillStyle = "black";
//   ctx.strokeStyle = "blue";              ctx.fillRect(0,0,board.width, board.height);
//   ctx.strokeRect(0,0,board.width, board.height);
// }

// function drawLine() {
//   for (var i = 0; i < layout.length; i++) {
//     let squares = layout[i];
//     if (squares === 0) {

//     }
//   }
// }

// function drawPacman() {
//   ctx.beginPath();
//   ctx.arc(pacmanPosition.x, pacmanPosition.y, 10, 0.25 * Math.PI, 1.25 * Math.PI, false);
//   ctx.fillStyle = "rgb(255, 255, 0)";
//   ctx.fill();
//   ctx.beginPath();
//   ctx.arc(pacmanPosition.x, pacmanPosition.y, 10, 0.75 * Math.PI, 1.75 * Math.PI, false);
//   ctx.fill();
//   // ctx.beginPath();
//   // ctx.arc(100, 75, 10, 0, 2 * Math.PI, false);
//   // ctx.fillStyle = "rgb(0, 0, 0)";
//   // ctx.fill();
// }

// function drawPellets() {
//   ctx.beginPath();
//   ctx.arc(50, 50, 3, 0,  2 * Math.PI, false);
//   ctx.fillStyle = "blue";
//   ctx.fill();
// }

// function drawGhosts(){
//   ctx.beginPath();
//         ctx.fillStyle = "blue";
//         ctx.arc(150 , 150, 10, Math.PI, 2* Math.PI);
//         ctx.lineTo(150 + 10, 150 + 10);
//         ctx.arc(150 + 10 / 2, 150 + 10, 10 * 0.5, 0, Math.PI);
//         ctx.arc(150 + 10 / 2 - 10 , 150 + 10,10 * 0.5, 0, Math.PI);
//         ctx.closePath();
//         ctx.fill();
//         ctx.strokeStyle = "blue";
//         ctx.stroke();
// }

// function movePacman(){

// }

// function randomMove(){

// }

// function changeDirection() {

// }

// function addScore() {
//   score += 10;
//   document.getElementById("score").innerHTML = score;
// }

// function lifeLost(){
//   lives -= 1;
//   document.getElementById("lives").innerHTML = lives;
// }



// document.addEventListener('DOMContentLoaded', () => {

//   const scoreDisplay = document.getElementById('score')
//   const width = 28
//   let score = 0
//   const grid = document.querySelector('.grid')
//   const layout = [
//     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
//     1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,3,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,3,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
//     1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,
//     1,1,1,1,1,1,0,1,1,4,4,4,4,4,4,4,4,4,4,1,1,0,1,1,1,1,1,1,
//     1,1,1,1,1,1,0,1,1,4,1,1,1,2,2,1,1,1,4,1,1,0,1,1,1,1,1,1,
//     1,1,1,1,1,1,0,1,1,4,1,2,2,2,2,2,2,1,4,1,1,0,1,1,1,1,1,1,
//     4,4,4,4,4,4,0,0,0,4,1,2,2,2,2,2,2,1,4,0,0,0,4,4,4,4,4,4,
//     1,1,1,1,1,1,0,1,1,4,1,2,2,2,2,2,2,1,4,1,1,0,1,1,1,1,1,1,
//     1,1,1,1,1,1,0,1,1,4,1,1,1,1,1,1,1,1,4,1,1,0,1,1,1,1,1,1,
//     1,1,1,1,1,1,0,1,1,4,1,1,1,1,1,1,1,1,4,1,1,0,1,1,1,1,1,1,
//     1,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,
//     1,3,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,3,1,
//     1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,
//     1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,
//     1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,
//     1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,
//     1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,
//     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
//     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
//   ]
//   // 0 - pac-dots
//   // 1 - wall
//   // 2 - ghost-lair
//   // 3 - power-pellet
//   // 4 - empty

//   const squares = []

//   //create your board
//   function createBoard() {
//     for (let i = 0; i < layout.length; i++) {
//       const square = document.createElement('div')
//       grid.appendChild(square)
//       squares.push(square)

//       //add layout to the board
//       if(layout[i] === 0) {
//         squares[i].classList.add('pac-dot')
//       } else if (layout[i] === 1) {
//         squares[i].classList.add('wall')
//       } else if (layout[i] === 2) {
//         squares[i].classList.add('ghost-lair')
//       } else if (layout[i] === 3) {
//         squares[i].classList.add('power-pellet')
//       }
//     }
//   }
//   createBoard()


//   //create Characters
//   //draw pacman onto the board
//   let pacmanCurrentIndex = 490
//   squares[pacmanCurrentIndex].classList.add('pac-man')
//   //get the coordinates of pacman on the grid with X and Y axis
//   // function getCoordinates(index) {
//   //   return [index % width, Math.floor(index / width)]
//   // }

//   // console.log(getCoordinates(pacmanCurrentIndex))

//   //move pacman
//   function movePacman(e) {
//     squares[pacmanCurrentIndex].classList.remove('pac-man')
//     switch(e.keyCode) {
//       case 37:
//         if(
//           pacmanCurrentIndex % width !== 0 &&
//           !squares[pacmanCurrentIndex -1].classList.contains('wall') &&
//           !squares[pacmanCurrentIndex -1].classList.contains('ghost-lair')
//           )
//         pacmanCurrentIndex -= 1
//         if (squares[pacmanCurrentIndex -1] === squares[363]) {
//           pacmanCurrentIndex = 391
//         }
//         break
//       case 38:
//         if(
//           pacmanCurrentIndex - width >= 0 &&
//           !squares[pacmanCurrentIndex -width].classList.contains('wall') &&
//           !squares[pacmanCurrentIndex -width].classList.contains('ghost-lair')
//           ) 
//         pacmanCurrentIndex -= width
//         break
//       case 39:
//         if(
//           pacmanCurrentIndex % width < width - 1 &&
//           !squares[pacmanCurrentIndex +1].classList.contains('wall') &&
//           !squares[pacmanCurrentIndex +1].classList.contains('ghost-lair')
//         )
//         pacmanCurrentIndex += 1
//         if (squares[pacmanCurrentIndex +1] === squares[392]) {
//           pacmanCurrentIndex = 364
//         }
//         break
//       case 40:
//         if (
//           pacmanCurrentIndex + width < width * width &&
//           !squares[pacmanCurrentIndex +width].classList.contains('wall') &&
//           !squares[pacmanCurrentIndex +width].classList.contains('ghost-lair')
//         )
//         pacmanCurrentIndex += width
//         break
//     }
//     squares[pacmanCurrentIndex].classList.add('pac-man')
//     pacDotEaten()
//     powerPelletEaten()
//     checkForGameOver()
//     checkForWin()
//   }
//   document.addEventListener('keyup', movePacman)

//   // what happens when you eat a pac-dot
//   function pacDotEaten() {
//     if (squares[pacmanCurrentIndex].classList.contains('pac-dot')) {
//       score++
//       scoreDisplay.innerHTML = score
//       squares[pacmanCurrentIndex].classList.remove('pac-dot')
//     }
//   }

//   //what happens when you eat a power-pellet
//   function powerPelletEaten() {
//     if (squares[pacmanCurrentIndex].classList.contains('power-pellet')) {
//       score +=10
//       ghosts.forEach(ghost => ghost.isScared = true)
//       setTimeout(unScareGhosts, 10000)
//       squares[pacmanCurrentIndex].classList.remove('power-pellet')
//     }
//   }

//   //make the ghosts stop flashing
//   function unScareGhosts() {
//     ghosts.forEach(ghost => ghost.isScared = false)
//   }

//   //create ghosts using Constructors
//   class Ghost {
//     constructor(className, startIndex, speed) {
//       this.className = className
//       this.startIndex = startIndex
//       this.speed = speed
//       this.currentIndex = startIndex
//       this.isScared = false
//       this.timerId = NaN
//     }
//   }

//   //all my ghosts
//   ghosts = [
//     new Ghost('blinky', 348, 250),
//     new Ghost('pinky', 376, 400),
//     new Ghost('inky', 351, 300),
//     new Ghost('clyde', 379, 500)
//     ]

//   //draw my ghosts onto the grid
//   ghosts.forEach(ghost => {
//     squares[ghost.currentIndex].classList.add(ghost.className)
//     squares[ghost.currentIndex].classList.add('ghost')
//     })

//   //move the Ghosts randomly
//   ghosts.forEach(ghost => moveGhost(ghost))

//   function moveGhost(ghost) {
//     const directions =  [-1, +1, width, -width]
//     let direction = directions[Math.floor(Math.random() * directions.length)]

//     ghost.timerId = setInterval(function() {
//       //if the next squre your ghost is going to go to does not have a ghost and does not have a wall
//       if  (!squares[ghost.currentIndex + direction].classList.contains('ghost') &&
//         !squares[ghost.currentIndex + direction].classList.contains('wall') ) {
//           //remove the ghosts classes
//           squares[ghost.currentIndex].classList.remove(ghost.className)
//           squares[ghost.currentIndex].classList.remove('ghost', 'scared-ghost')
//           //move into that space
//           ghost.currentIndex += direction
//           squares[ghost.currentIndex].classList.add(ghost.className, 'ghost')
//       //else find a new random direction ot go in
//       } else direction = directions[Math.floor(Math.random() * directions.length)]

//       //if the ghost is currently scared
//       if (ghost.isScared) {
//         squares[ghost.currentIndex].classList.add('scared-ghost')
//       }

//       //if the ghost is currently scared and pacman is on it
//       if(ghost.isScared && squares[ghost.currentIndex].classList.contains('pac-man')) {
//         squares[ghost.currentIndex].classList.remove(ghost.className, 'ghost', 'scared-ghost')
//         ghost.currentIndex = ghost.startIndex
//         score +=100
//         squares[ghost.currentIndex].classList.add(ghost.className, 'ghost')
//       }
//     checkForGameOver()
//     }, ghost.speed)
//   }

//   //check for a game over
//   function checkForGameOver() {
//     if (squares[pacmanCurrentIndex].classList.contains('ghost') &&
//       !squares[pacmanCurrentIndex].classList.contains('scared-ghost')) {
//       ghosts.forEach(ghost => clearInterval(ghost.timerId))
//       document.removeEventListener('keyup', movePacman)
//       setTimeout(function(){ alert("Game Over"); }, 500)
//     }
//   }

//   //check for a win - more is when this score is reached
//   function checkForWin() 
//     if (score === 274) {
//       ghosts.forEach(ghost => clearInterval(ghost.timerId))
//       document.removeEventListener('keyup', movePacman)
//       setTimeout(function(){ alert("You have WON!"); }, 500)
//     }
//   }
// })
<body>
  <div> Score: <span id="score">0</span></div>
  <div> Lives: <span id="lives">3</span></div>
  <canvas id="pacmanBoard"></canvas>

</body>


<!-- <body>
    <div class="grid"></div>

    <h3>Score:<span id="score"></span></h3>

  </body> -->

Full codepen can be found here .. https://codepen.io/tallulahh/pen/jOMNPjB?editors=1111

thanks in advance!

3
  • This would probably get better answers in gamedev.stackexchange.com Commented Jan 25, 2021 at 19:26
  • 1
    I think it's OK to ask here, but a minimal reproducible example would be nice. Codepen has a lot of irrelevant commented out code so it's really hard to follow the logic quickly. In the codepen, intersectRect isn't even called, and it's not called on every wall even in the commented-out chunk, so it's unclear to me what your attempt/strategy is in fact. This pen seems similar to what you're going for (using a 2d array to encode the map), minus gravity. I'll come back to this if I have time later. Commented Jan 25, 2021 at 19:28
  • I thought I had deleted all the comments. Have edited that now! My thought process has been all over the place hence all the commenting out. Thanks for referring the other pen it is helpful. Commented Jan 25, 2021 at 19:43

1 Answer 1

1

In pacman collision can be oversimplified by just using an array and checking wether the current case where pacman is contains something or not, if so make him return to previous position.

const myCharacter = {x:2,y:2,prevpos:{}};
let ctx = can.getContext("2d");

let gamegrid=[];

for(let i = 0;i<=10;i++)
{
  let tempgrid = []
  for(let j = 0;j<=10;j++)
  {
    tempgrid.push(0);
    }
  gamegrid.push(tempgrid);
}

for(let buildAWall = 0;buildAWall<=10;buildAWall++)
{
  gamegrid[buildAWall][0] = gamegrid[0][buildAWall] = gamegrid[buildAWall][10] = gamegrid[10][buildAWall] = 1;
  ctx.fillRect(buildAWall*32, 0, 32, 32);
  ctx.fillRect(0, buildAWall*32, 32, 32);
  ctx.fillRect(10*32, buildAWall*32, 32, 32);
  ctx.fillRect(buildAWall*32, 10*32,32, 32);
  }
  
const drawcharacter = ()=>{
  ctx.clearRect(32,32, 9*32, 9*32);
  ctx.fillStyle = "blue";
  ctx.fillRect(myCharacter.x*32,myCharacter.y*32,32,32);
};

document.addEventListener("keydown",(e)=>{
  myCharacter.prevpos={x:myCharacter.x,y:myCharacter.y};
  myCharacter.y-=e.key=="ArrowUp";
  myCharacter.y+=e.key=="ArrowDown";
  myCharacter.x-=e.key=="ArrowLeft";
  myCharacter.x+=e.key=="ArrowRight";
  //here goes all the magic simply checking the grid
  if(gamegrid[myCharacter.x][myCharacter.y])
  {
    myCharacter.x=myCharacter.prevpos.x;
    myCharacter.y=myCharacter.prevpos.y;
  }
  drawcharacter();
});
<canvas id="can" height=500 width=500>

</canvas>

The ghosts are a bit more tricky you need to check if pacman's position equals to a ghost's position

const myCharacter = {x:2,y:2,prevpos:{}};
const someGhost = {x:5,y:5,prevpos:{}};
let gameTimeout = undefined;
let ctx = can.getContext("2d");

let gamegrid=[];

for(let i = 0;i<=10;i++)
{
  let tempgrid = []
  for(let j = 0;j<=10;j++)
  {
    tempgrid.push(0);
    }
  gamegrid.push(tempgrid);
}

for(let buildAWall = 0;buildAWall<=10;buildAWall++)
{
  gamegrid[buildAWall][0] = gamegrid[0][buildAWall] = gamegrid[buildAWall][10] = gamegrid[10][buildAWall] = 1;
  ctx.fillRect(buildAWall*32, 0, 32, 32);
  ctx.fillRect(0, buildAWall*32, 32, 32);
  ctx.fillRect(10*32, buildAWall*32, 32, 32);
  ctx.fillRect(buildAWall*32, 10*32,32, 32);
  }
  
const drawcharacter = ()=>{
  ctx.fillStyle = "blue";
  ctx.fillRect(myCharacter.x*32,myCharacter.y*32,32,32);
};

const drawenemies = ()=>{
  ctx.fillStyle = "red";
  ctx.fillRect(someGhost.x*32,someGhost.y*32,32,32);
};

const redraw = ()=>{
  if(!gameTimeout)
  {
    ctx.clearRect(32,32, 9*32, 9*32);
    drawenemies();
    drawcharacter();
    }
}

const moveenemies = ()=>{
  someGhost.prevpos={x:someGhost.x,y:someGhost.y};
  someGhost.x += Math.floor(Math.random()*2)?1:-1;
  someGhost.y += Math.floor(Math.random()*2)?1:-1;
  if(gamegrid[someGhost.x][someGhost.y])
  {
    someGhost.x=someGhost.prevpos.x;
    someGhost.y=someGhost.prevpos.y;
  }
  if((someGhost.x==myCharacter.x)&&(someGhost.y==myCharacter.y))
  gameTimeout = true;
  redraw();
  setTimeout(()=>{moveenemies();},1000);
};

drawcharacter();
moveenemies();

document.addEventListener("keydown",(e)=>{
  myCharacter.prevpos={x:myCharacter.x,y:myCharacter.y};
  myCharacter.y-=e.key=="ArrowUp";
  myCharacter.y+=e.key=="ArrowDown";
  myCharacter.x-=e.key=="ArrowLeft";
  myCharacter.x+=e.key=="ArrowRight";
  //here goes all the magic simply checking the grid
  if(gamegrid[myCharacter.x][myCharacter.y])
  {
    myCharacter.x=myCharacter.prevpos.x;
    myCharacter.y=myCharacter.prevpos.y;
  }
  //here is the check for the ghost
  if((someGhost.x==myCharacter.x)&&(someGhost.y==myCharacter.y))
  gameTimeout = true;
  redraw();
});
<canvas id="can" height=500 width=500></canvas>

note : it would be better to separate the checks from the ghostmove function and player move event just to avoid repeating it.

Also you might have some interpolation smoothing the animation for you which in this case you may want to use real collisions like you tried, i can suggest you to rather use spherical collision which are simpler and more efficient in this case

const myCharacter = {x:2,y:2,prevpos:{}};
const someGhost = {x:5,y:5,prevpos:{}};
let gameTimeout = undefined;
let ctx = can.getContext("2d");

let gamegrid=[];

for(let i = 0;i<=10;i++)
{
  let tempgrid = []
  for(let j = 0;j<=10;j++)
  {
    tempgrid.push(0);
    }
  gamegrid.push(tempgrid);
}

for(let buildAWall = 0;buildAWall<=10;buildAWall++)
{
  gamegrid[buildAWall][0] = gamegrid[0][buildAWall] = gamegrid[buildAWall][10] = gamegrid[10][buildAWall] = 1;
  ctx.fillRect(buildAWall*32, 0, 32, 32);
  ctx.fillRect(0, buildAWall*32, 32, 32);
  ctx.fillRect(10*32, buildAWall*32, 32, 32);
  ctx.fillRect(buildAWall*32, 10*32,32, 32);
  }
  
const drawcharacter = ()=>{
  ctx.fillStyle = "blue";
  ctx.fillRect(myCharacter.x*32,myCharacter.y*32,32,32);
};

const drawenemies = ()=>{
  ctx.fillStyle = "red";
  ctx.fillRect(someGhost.x*32,someGhost.y*32,32,32);
};

const redraw = ()=>{
  if(!gameTimeout)
  {
    ctx.clearRect(32,32, 9*32, 9*32);
    drawenemies();
    drawcharacter();
    }
}

const moveenemies = ()=>{
  someGhost.prevpos={x:someGhost.x,y:someGhost.y};
  someGhost.x += Math.floor(Math.random()*2)?1:-1;
  someGhost.y += Math.floor(Math.random()*2)?1:-1;
  if(gamegrid[someGhost.x][someGhost.y])
  {
    someGhost.x=someGhost.prevpos.x;
    someGhost.y=someGhost.prevpos.y;
  }
  if(checkCollision(someGhost,myCharacter))
    gameTimeout = true;
  redraw();
  setTimeout(()=>{moveenemies();},1000);
};

const checkCollision = (a,b)=>{
  return ((((a.x*32)-(b.x*32)<32)&&((a.y*32)-(b.y*32)<32))&&
  (((a.x*32)-(b.x*32)>=0)&&((a.y*32)-(b.y*32)>=0)))
};

drawcharacter();
moveenemies();

document.addEventListener("keydown",(e)=>{
  myCharacter.prevpos={x:myCharacter.x,y:myCharacter.y};
  myCharacter.y-=e.key=="ArrowUp";
  myCharacter.y+=e.key=="ArrowDown";
  myCharacter.x-=e.key=="ArrowLeft";
  myCharacter.x+=e.key=="ArrowRight";
  //here goes all the magic simply checking the grid
  if(gamegrid[myCharacter.x][myCharacter.y])
  {
    myCharacter.x=myCharacter.prevpos.x;
    myCharacter.y=myCharacter.prevpos.y;
  }
  //here is the check for the ghost
  if(checkCollision(myCharacter,someGhost))
    gameTimeout = true;
  redraw();
});
<canvas id="can" height=500 width=500></canvas>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much! This helped me get my head around it. I was struggling to add properties to each grid block but have used the method you suggested and its working great. Still ploughing through the project!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.