I've made a codepen in order to better explain my situation. https://codepen.io/kennyfully1988/pen/yLqpBVp
I'm working on a game where the player collects apples. The collision is working correctly when a player touches an apple. (The player will get 1 point and the apple will be erased from the apples array).
What I'm confused about is the following function
checkSolidCollisions(walls) {
// check to see if player is colliding with walls
for (let i = 0; i < walls.length; i++) {
if (
this.dx <= walls[i].x + walls[i].width &&
this.dx + this.dw >= walls[i].x &&
this.dy <= walls[i].y + walls[i].height &&
this.dy + this.dh >= walls[i].y
) {
console.log(true);
return true;
}
}
return false;
}
I created this function hoping that this will be a check to see if the player is in collision with a wall (the wall array). However, it doesn't seem to work at all. I'm willing to provide as much information as needed in order to solve this problem. I want you all to know that this is OOP JavaScript.
So, what I tried to do is make the player not be able to pass the wall. However, the player always passes the wall.
So after a long time of testing everything out and rebuilding samples, I noticed what I did wrong. I didn't write the proper logic to see what happens after the player collides with the wall, such as pushing the player back into a safer position after the collision.
// Working code
'use strict';
window.onload = () => {
const gameBox = document.querySelector('.game-box');
const ctx = gameBox.getContext('2d');
const collisionCheckerLabel = document.querySelector(
'.collision-checker-label',
);
let collisionChecker = false;
const playerImage = new Image();
playerImage.src =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAApNJREFUeJztm7FuwjAQhg/Eg4QwsDEFiYGVZ2DhPXgG3oOl6iN0zVApnbpVqC0rb9Ahwh2QLcfY8V0S20W9fwGj5D7f1Q253wEgoPKsEHlWiJCMvhphDtKT+Dq/oc/5eB8DAMB8cSWdR2X10QQzGZkIAMB8UQjsxOaLK2kyetEkC4BWiLYVZ4tjDWwmricScwWYfF8Mk2m+t83jLqAZBAP2JdI3BqWQg64ATIC2iXRZAUPxsWoElOCnl1frwdvNCjWRrgmk4KsP8qwQErzdrBqTsI1twfokkJSfZ4WoTrWoTrXIs0IIIYT8zBxXp1o8lz933+9mDPneNf4r/DFYNJsuW8e2yut/vc/vSlXbHAMAHI5l68UqJv+uADKQ6/V8qVsn0yWBlPwxwO1/Qq+QXk05Pl9qBd/v1s4LUZcEUvK93wL6CfvdWk3YBOvLUEq/eJlxsBex0PxB7wP6JJCKH6TZiHkj8xf5LCn2A9gPYD9Anc9+APsB7Ac8jh/gU2g/ICZ/RIUD3G4vzfv5Pgmk5Fv9AKqoCfj8gJh8cgEw/XhIDc23+gEuMKYf9wnjB8TkB/UDXOBYfgCGz35AW8CuSt2Pp+azpNgPYD+A/QB1PvsB7AewH/BYfoC5J29OJLQfEItv9QPklvJsurQGw/TjlARS8p3tMGVL25WAq8PD+AGx+I0CbDerRuVc1ceIkkBK/gRA9eONKppwTDur7+e7lmCLH5CEz36A7WD2A3oqdT+ems+SYj+A/QD2A9T57AewH8B+wGP5ASY45u8FYvK9zwfYenPq/rwvgZR81PY45Xl9VwKU3wvE5HsLoPfmsl+nqos3EIuPej5APq9/OJZwOJak/XlMAin5/8YP0GOxH8B+AEvpF88gNOQKrAefAAAAAElFTkSuQmCC';
class Player {
constructor(config) {
this._rng = String(Math.floor(Math.random() * 100)).padEnd(3, '0'); // random number generator
this._id = `player_${new Date().getTime()}${this._rng}`; // generated id
this.image = playerImage;
this.currentFrame = 1; // helper variable to help with requestAnimationFrame()
this.totalFps = 60; // helper variable to help with requestAnimationFrame()
this.totalImageFrames = 4; // the number of frames in the sprite
this.sx = config?.sx || 0; // source x position
this.sy = config?.sy || 0; // source y position
this.sw = config?.sw || 16; // source width
this.sh = config?.sh || 16; // source height
this.dx = config?.dx || 0; //destination x position
this.dy = config?.dy || 0; //destination y position
this.dw = config?.dw || 16; //destination width
this.dh = config?.dh || 16; //destination height
this.animation = config?.animation || 0; // lazy way to play animations
this.movement = config?.movement || 'idle'; // player movement
window.addEventListener('keydown', (e) => {
e.preventDefault();
if (e.key === 'ArrowUp') {
this.movement = 'up';
} else if (e.key === 'ArrowDown') {
this.movement = 'down';
} else if (e.key === 'ArrowLeft') {
this.movement = 'left';
} else if (e.key === 'ArrowRight') {
this.movement = 'right';
} else {
this.movement = '';
}
});
window.addEventListener('keyup', (e) => {
e.preventDefault();
this.movement = 'idle';
});
}
render(ctx) {
ctx.drawImage(
this.image,
Math.floor(
this.currentFrame / (this.totalFps / this.totalImageFrames),
) * 16,
this.animation * 16,
this.sw,
this.sh,
this.dx,
this.dy,
this.dw,
this.dh,
);
}
update(ctx) {
// player animation
if (this.currentFrame >= this.totalFps - 1) {
this.currentFrame = 1;
} else {
this.currentFrame++;
}
// player movement
if (this.movement === 'up') {
this.animation = 1;
if (this.dy <= 0) return;
this.dy--;
} else if (this.movement === 'down') {
this.animation = 0;
if (this.dy + 16 >= ctx.canvas.height) return;
this.dy++;
} else if (this.movement === 'left') {
this.animation = 2;
if (this.dx <= 0) return;
this.dx--;
} else if (this.movement === 'right') {
this.animation = 3;
if (this.dx + 16 >= ctx.canvas.width) return;
this.dx++;
} else {
return;
}
}
}
class Rectangle {
constructor(config) {
this.color = config?.color || 'black';
this.x = config?.x || 0;
this.y = config?.y || 0;
this.width = config?.width || 16;
this.height = config?.height || 16;
}
render(ctx) {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
const rects = [
new Rectangle({ color: 'red', x: 32, y: 32 }),
new Rectangle({ color: 'green', x: 160 - 32, y: 160 - 32 }),
new Rectangle({ color: 'blue', x: 96, y: 96 }),
];
const player = new Player({ dx: 0, dy: 0 });
const renderScene = () => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
rects.forEach((rect) => {
rect.render(ctx);
});
player.render(ctx);
player.update(ctx);
requestAnimationFrame(() => renderScene());
for (let i = 0; i < rects.length; i++) {
if (
//Check x
player.dx + player.dw > rects[i].x && // right side
player.dx < rects[i].x + rects[i].width && // left side
// Check y
player.dy + player.dh > rects[i].y && // bottom side
player.dy < rects[i].y + rects[i].height // top side
) {
collisionChecker = true;
collisionCheckerLabel.innerText = collisionChecker;
if (player.movement === 'up') {
player.dy++;
} else if (player.movement === 'down') {
player.dy--;
} else if (player.movement === 'left') {
player.dx++;
} else if (player.movement === 'right') {
player.dx--;
}
return;
}
collisionChecker = false;
collisionCheckerLabel.innerText = collisionChecker;
}
};
renderScene();
};
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: lightgray;
height: 100vh;
}
.game-box {
border: 0.5rem solid black;
height: 90%;
image-rendering: pixelated;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<link rel="icon" type="image/x-icon" href="#" />
<link rel="stylesheet" href="app.css" />
<script defer src="app.js"></script>
<title>Rect Collisions</title>
</head>
<body>
<h1>Rect Collisions</h1>
<canvas class="game-box" width="160" height="160"></canvas>
<p>
Are the objects colliding? <span class="collision-checker-label">No</span>
</p>
</body>
</html>