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.
CodePudding user response:
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; e.g 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:
- Be sure to check first whether or not the move is a valid one, so the player does not fall off the map
- If a collision occurs, what should happen? If a collision doesn't occur, what should happen? I recommend writing down a list of your assumptions while coding and checking them as you go. Especially in collision detection, it can be very easy to have unintended bugs from unchecked assumptions.
Resources for Learning to do this:
How can I create a two dimensional array in JavaScript?
CodePudding user response:
Solution:
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
Calculating position:
Math.floor(y / tileH) // y
Math.floor(x / tileW) // x
Actual code:
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
}
}