无法检测在canvas javascript中绘制的对象的碰撞



嘿,我目前正在javascript构建一个简单的吃豆人作为一个学习项目。我能够渲染一个基本的板,吃豆人,颗粒和大颗粒与基本的画布图纸(弧等)。游戏对移动吃豆人的关键代码有反应,但当我想测试碰撞和访问画布绘图的x和y值时,我感到很困难。我的板子是在for循环中绘制的,该循环通过布局/网格2d数字数组进行迭代,并根据数字绘制不同的内容,0代表墙壁,1 -颗粒等。我觉得我可能在drawBoard for循环中也犯了一个错误。我已经开始在使用函数绘制墙壁和尝试访问其X和Y位置之间来回切换:

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); 
}

或在for循环中创建新的类对象,然后尝试访问x和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;
//     };
//   }

// }

为了检测碰撞,我尝试了两个不同的函数,如下所示,并尝试在Wall对象的方法中调用它们。

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));
// }

不用说,我非常困惑,如果有人能给我一个简单的方法来检测吃豆人是否触摸到一个画的墙或颗粒等。

//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> -->

完整的代码依赖可以在这里找到。https://codepen.io/tallulahh/pen/jOMNPjB?editors=1111

提前感谢!

在吃豆人碰撞中,可以通过使用数组并检查吃豆人所在的当前情况是否包含某些内容来过度简化,如果包含,则使他返回到先前的位置。

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>

鬼有点棘手,你需要检查吃豆人的位置是否等于鬼的位置

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>

注意:最好将检查与ghostmove函数和玩家移动事件分开,以避免重复。

你也可以有一些插值平滑动画,在这种情况下,你可能想要使用真正的碰撞,就像你尝试过的,我可以建议你使用球面碰撞,在这种情况下更简单,更有效

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>

最新更新