Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
150 views
in Technique[技术] by (71.8m points)

arrays - Cannot detect collision for objects drawn in canvas javascript

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...