I’m currently creating a game in native JavaScript, HTML, and a bit of CSS. I have 2 blocks named Sprites and whenever they go toward the left or right edge of the canvas, they don’t stop. Question: How can I use native JS to stop the sprites from moving off the canvas?
Note: All answers to this solution are in other languages or use libraries, so this question has not been answered.
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext("2d");
canvas.width = 1024;
canvas.height = 576;
function logMessage(msg) {
document.querySelector('#myMessage').textContent += msg + '. ';
}
//This creates a background
ctx.fillRect(0, 0, canvas.width, canvas.height);
//Cahnging this value changes how fast the sprites fall
const gravity = 0.7;
class Sprite {
//The curly braces makes it easier to pass values back and forth
constructor({position, velocity}) {
this.position = position;
this.velocity = velocity;
this.height = 150;
this.lastKey;
}
draw() {
ctx.fillStyle = 'red';
//Because this is inside of the class "Sprite",
//We can use "this." to give us the position/velocity/whatever that is being used in this instance
ctx.fillRect(this.position.x, this.position.y, 50, this.height);
}
update() {
this.draw();
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
//Stops the sprite from moving off the edge of the canvas
if (this.position.x <= 0 || this.position.x + 50 >= canvas.width) {
logMessage("Hi")
this.velocity.x == 0;
}
//Stops the velocity in the y direction if the sprite hits the bottom
if (this.position.y + this.height + this.velocity.y >= canvas.height) {
this.velocity.y = 0;
} else {
this.velocity.y += gravity;
}
}
}
const Player = new Sprite({
position: {
x: 0,
y: 0
},
velocity: {
x: 0,
y: 0
}
})
const Enemy = new Sprite({
position: {
x: 400,
y: 100
},
velocity: {
x: 0,
y: 0
}
})
const keys = {
w: {
pressed: false
},
a: {
pressed: false
},
d: {
pressed: false
},
ArrowUp: {
pressed: false
},
ArrowLeft: {
pressed: false
},
ArrowRight: {
pressed: false
}
}
function animate() {
//This makes the animate method run over and over
window.requestAnimationFrame(animate);
//The two below fill in the background so that when the sprites move, the background stays the same
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
Player.update();
Enemy.update();
//Player movement
Player.velocity.x = 0; //This stops the sprite from continuously moving
if (keys.a.pressed == true && Player.lastKey == "a") {
Player.velocity.x = -5; //Changing this value will change how fast the sprite moves left
} else if (keys.d.pressed == true && Player.lastKey == "d") {
Player.velocity.x = 5;
}
//Enemy movement
Enemy.velocity.x = 0;
if (keys.ArrowLeft.pressed == true && Enemy.lastKey == "ArrowLeft") {
Enemy.velocity.x = -5;
} else if (keys.ArrowRight.pressed == true && Enemy.lastKey == "ArrowRight") {
Enemy.velocity.x = 5;
}
}
animate();
//Event listeners that move the player when certain keys are pressed
window.addEventListener('keydown', (event) => {
switch (event.key) {
//Player movement
case 'w':
Player.velocity.y = -20;
break;
case 'a':
keys.a.pressed = true;
//This keeps track of our last pressed key so our sprite does what was pressed most recently
Player.lastKey = "a";
break
case 'd':
keys.d.pressed = true;
Player.lastKey = "d";
break;
}
//Enemy movement
switch (event.key) {
case 'ArrowUp':
Enemy.velocity.y = -20;
break;
case 'ArrowRight':
keys.ArrowRight.pressed = true;
Enemy.lastKey = 'ArrowRight'
break
case 'ArrowLeft':
keys.ArrowLeft.pressed = true;
Enemy.lastKey = 'ArrowLeft'
break;
}
})
window.addEventListener('keyup', (event) => {
//Player keys
switch (event.key) {
case 'w':
keys.w.pressed = false;
break;
case 'a':
keys.a.pressed = false;
break
case 'd':
keys.d.pressed = false;
break;
}
//Enemy keys
switch (event.key) {
case 'ArrowUp':
keys.ArrowUp.pressed = false;
break;
case 'ArrowLeft':
keys.ArrowLeft.pressed = false;
break
case 'ArrowRight':
keys.ArrowRight.pressed = false;
break;
}
})
#myConsole {
background-color: black;
color: white;
min-height: 100px;
}
<!DOCTYPE html>
<html lang="en">
<html>
<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">
<meta name="author" content="Christian Davis">
<link rel="stylesheet" href="styles.css">
<title>Fighting Game</title>
</head>
<body>
<canvas id="canvas"></canvas>
<p id="myConsole">> <span id="myMessage"></span></p>
<script src="app.js"></script>
</body>
</html>
2
Answers
After reading @Rory McCrossan's solution, I came up with my own that keeps the sprites inside the bounds of the canvas completely.
The issue is because your logic to determine the extents of the canvas was flawed.
You can simplify the logic by locking the bounds of
position.x
usingMath.min()
andMath.max()
. I would suggest adding awidth
property to your sprites to avoid having to use the magic number.Here’s a working example, note that I commented out the other sprite to make the effect more clear.