I've been looking for some time now how to detect collisions on a tilemap between my player and the box specified in my table, but all I found are advanced tutorials, I'm trying to do this as simply as possible so that I can understand how it works too. In my table, I therefore seek to detect a collision only if the player walks on a box of value 1 (this would be a wall for example). Then the player will not be able to move on this place of my map.
My code:
// Initi ctx = null; var ctx = document.getElementById("canvas").getContext("2d"); // Map var gameMap = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; var tileW = 40, tileH = 40; var mapW = 10, mapH = 10; window.onload = function() { requestAnimationFrame(drawGame); ctx.font = "bold 10pt sans-serif"; }; // Player var x = 100; var y = 100; var radius = 10; var upPressed = false; var downPressed = false; var leftPressed = false; var rightPressed = false; var speed = 1; function drawPlayer() { ctx.fillStyle = "green"; ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2) ctx.fill(); } // Inputs function inputs() { if (upPressed) { y = y - speed; } if (downPressed) { y = y + speed; } if (leftPressed) { x = x - speed; } if (rightPressed) { x = x + speed; } } document.body.addEventListener("keydown", keyDown) document.body.addEventListener("keyup", keyUp) function keyDown(event) { if (event.keyCode == 38) { upPressed = true; } if (event.keyCode == 40) { downPressed = true; } if (event.keyCode == 37) { leftPressed = true; } if (event.keyCode == 39) { rightPressed = true; } if (event.keyCode == 65) { speedCodePressed = true; speed = 20; } if (event.keyCode == 32) { shootPressed = true; } } function keyUp(event) { if (event.keyCode == 38) { upPressed = false; } if (event.keyCode == 40) { downPressed = false; } if (event.keyCode == 37) { leftPressed = false; } if (event.keyCode == 39) { rightPressed = false; } if (event.keyCode == 32) { shootPressed = false; } } // game map draw function function drawMap() { if (ctx == null) { return; } for (var y = 0; y < mapH; ++y) { for (var x = 0; x < mapW; ++x) { switch (gameMap[((y * mapW) + x)]) { case 0: ctx.fillStyle = "#685b48"; break; default: ctx.fillStyle = "#5aa457"; } ctx.fillRect(x * tileW, y * tileH, tileW, tileH); } } } // clear screen function clearScreen() { ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); } // game loop function drawGame() { requestAnimationFrame(drawGame); clearScreen(); drawMap(); drawPlayer(); inputs(); }
<canvas id="canvas"></canvas>
I won't go into too much detail, as I think it's pretty straightforward, but I'm a beginner and really have no idea.
One way to solve this is by changing your game map from a 1 dimensional array to a 2 dimensional array.
So instead of:
var gameMap = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 0, 1, 0, 0, 0, 1, 1, 0,
0, 1, 0, 1, 0, 1, 0, 0, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
Make it:
let gameMap = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
[0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 0, 0, 0, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];
Or however you want to structure your game's map.
Then once you have this 2D array, keep track of the row and column index of where your player is currently located.
let player_index_x = 3;
let player_index_y = 5;
Update this index whenever the player changes locations; eg if the player moves up 1, then you subtract 1 from the y index. If the player moves right 1, add one to the x index.
Then collision detection becomes a lot more straightforward because before moving left, right, up, or down, you can check something like:
if(left_pressed)
{
// make sure that it is indeed possible to move left
if(player_index_x > 1)
{
if(gameMap[player_index_x - 1][player_index_y] == 1)
{
// collision detected, do not move, return if in function
}
else
{
// move player
player_index_x -= 1;
}
}
}
My Recommendations:
Resources for Learning to do this:
See the changes below...
canvas.height = tileH * mapH
same for width to match the real size of the game.var player = { x: 100, y: 100, radius: 10, speed: 1 }
you should keep everything related to the player in that objectPath2D
to create the structure that we draw (walls) and a path that we use for the collisionsisPointInPath
read more here: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPathgameMap
to a 2 dimensional array its makes everything easier now that we are using the Path2D, not really required but I like it better that way. var canvas = document.getElementById("canvas") var tileW = 40 var tileH = 40 var mapW = 10 var mapH = 10 var ctx = canvas.getContext("2d"); var upPressed = false; var downPressed = false; var leftPressed = false; var rightPressed = false var player = { x: 100, y: 100, radius: 10, speed: 1 } var gameMap = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], [0, 1, 0, 1, 0, 0, 0, 1, 1, 0], [0, 1, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ]; var path = new Path2D() var walls = new Path2D() window.onload = function() { canvas.height = tileH * mapH canvas.width = tileW * mapW for (var y = 0; y < mapH; ++y) { for (var x = 0; x < mapW; ++x) { if (gameMap[y][x]) { path.rect(x * tileW- player.radius, y * tileH- player.radius, tileW + player.radius*2, tileH + player.radius*2) walls.rect(x * tileW, y * tileH, tileW, tileH) } } } requestAnimationFrame(drawGame); }; function drawPlayer() { ctx.fillStyle = "green"; ctx.beginPath(); ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2) ctx.fill(); } function inputs() { var newx = player.x var newy = player.y if (upPressed) newy = player.y - player.speed; if (downPressed) newy = player.y + player.speed; if (leftPressed) newx = player.x - player.speed; if (rightPressed) newx = player.x + player.speed; if (.ctx,isPointInPath(path, newx. newy)) { player;x = newx. player;y = newy. } } document.body,addEventListener("keydown". keyDown) document.body,addEventListener("keyup". keyUp) function keyDown(event) { if (event;keyCode == 38) upPressed = true. if (event;keyCode == 40) downPressed = true. if (event;keyCode == 37) leftPressed = true. if (event;keyCode == 39) rightPressed = true. } function keyUp(event) { if (event;keyCode == 38) upPressed = false. if (event;keyCode == 40) downPressed = false. if (event;keyCode == 37) leftPressed = false. if (event;keyCode == 39) rightPressed = false. } function drawGame() { ctx.fillStyle = "#685b48" ctx,fillRect(0, 0. canvas,width. canvas;height). ctx.fillStyle = "#5aa457" ctx.fill(walls) //ctx;stroke(path); drawPlayer(); inputs(); requestAnimationFrame(drawGame); }
<canvas id="canvas"></canvas>
Check if the new position is not 1
in the game map.
If it's 1
do nothing.
If it's not 1
assign position
Math.floor(y / tileH) // y
Math.floor(x / tileW) // x
function inputs() {
let newX = x
let newY = y
if(upPressed) {
newY -= speed
}
if(downPressed) {
newY += speed
}
if(leftPressed) {
newX -= speed
}
if(rightPressed) {
newX += speed
}
if (gameMap[Math.floor(newY / tileH)][Math.floor(newX / tileW)] !== 1) {
x = newX
y = newY
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.