how can I detect collision in a 2D tile game map

Multi tool use
Multi tool use


how can I detect collision in a 2D tile game map



I made this basic game where I drew a map and a player, the player can move anywhere but how can I make so that it wont move when its on the tile[1] in the map?
also when I try to check if the player.x is greater than 50 it could go left it works but than if I click 2 keys at once it goes through
const context = document.querySelector("canvas").getContext("2d");


var rgb = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random() + ')';

document.onload = Loop();

var width = 1500;
var height = 800;

function Loop(){

var width = 1500;
var height = 800;

context.canvas.height = height;
context.canvas.width = width;

this.interval = setInterval(Update, 1000/100);

}



const Player = function(x, y, w, h, color) {
this.x = x; this.y = y; this.w = w; this.h = h;

this.speedY = 0; this.speedX = 0;
this.Draw = function(){
context.fillStyle = this.color;
context.fillRect(this.x, this.y, this.w, this.h);
};
this.Move = function(){
this.x += this.speedX;
this.y += this.speedY;
};
};<code>

var player = new Player(100,100,50, 50, rgb);


var Key = {};
function Update(){
context.clearRect(0, 0, width, height);
Map();
player.Draw();
player.Move();

onkeydown = onkeyup = function(e){
player.speedX = 0;
player.speedY = 0;
e = e || event;
Key[e.keyCode] = e.type == 'keydown';
if(Key[37] || Key[65]) {player.speedX -= 2}
if(Key[38] || Key[87]) {player.speedY -= 2}
if(Key[39] || Key[68]) {player.speedX += 2}
if(Key[40] || Key[83]) {player.speedY += 2}
if(Key[32]) {player.color = 'rgb(' + Math.random()*256 + ',' + Math.random()*256 + ',' + Math.random()*256 + ','+Math.random()*1 + ')';}
};
}

var map = [
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1
];

var row = 5;
var column = 5;


function Map(){
for(let y = -1; y < column; y++){

for(let x = -1; x < row; x++){
switch(map[((y*row) + x)]) {
case 0: context.fillStyle = player.color;
break;
case 1: context.fillStyle = "#ffffff";
break;
default: context.fillStyle = "#000000";
}
context.fillRect(x*50, y*50, 50, 50);

}
}
}




2 Answers
2



Firstly, looking at your code, there are some things that are missing which is required to implement basic collision detection and those are:



The player's current direction that he/she is moving in. This is important because it allows the function determining the collision detection to distinguish which side it is checking for the collision (Up, down, left, or right) since a player can only collide with one side at a time.



The tile's position and size. This is also very important because like the first point, there is only one side of the tile that the player can collide with and knowing the size and position can determine if it is a collision or not based on the players size and position.



Also, since you mentioned it is a basic game, the implementation below is a basic collision detection. If you were to make a more complex and bigger game, you should try looking into quad trees for more efficient collision detection:
https://gamedevelopment.tutsplus.com/tutorials/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space--gamedev-374



Now this is the function for detecting collision, for the sake of readability and shortness, p will represent the player object and t would represent the tile object. This function returns whether or not the player is colliding with a tile based on their direction of movement.


function isColliding(p, t){
if (p.direction == 'up') {
return p.y +(p.height/2)-p.speedY< t.y + t.height && p.y > t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'down') {
return p.y + (p.height/2)+p.speedY > t.y && p.y < t.y
&& p.x + p.width > t.x && p.x < t.x + t.width;
}
if (p.direction == 'right') {
return p.x + p.width+p.speedX > t.x && p.x < t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
if (p.direction == 'left') {
return p.x -p.speedX< t.x + t.width && p.x > t.x
&& p.y +(p.height/2)> t.y && p.y + p.height < t.y +t.height+ (p.height / 2);
}
return false;
}



You would probably want to put this in the player move function to constantly detect for tiles as it is moving. To do that, you'd want to modify your keydown detection so that with each different keydown, it would update the player's direction, here's a simple example:


document.onkeydown = function(event){
if (event.keyCode == 87)
player.up = true;
else if (event.keyCode == 65)
player.left = true;
else if (event.keyCode == 83)
player.down = true;
else if (event.keyCode == 68)
player.right = true;
}



and another simple example for every time the player moves (user presses a keydown):


const Player= function(/*Param stuff*/){
/*Property stuff*/
//tileArray is the array (or object, your choice) of all the current tiles in the map
this.move=function(tileArray){
//Go through all tiles to see if player is colliding with any of them
for(var t in tileArray){
if(this.up){
if(isColliding(this, tileArray[t]){
//functionality for when player collides
}else{
//functionality for when player doesn't collide
}
}
//check if player is going down, left, etc
}
}
}



These are just examples of how to implement the detection. You should use it as a reference to implement it relatively to how your code function because I didn't write it based on what you posted.



PS.



Make sure to also convert the directions to false after the user stops pressing the key.





is tileArray like: map = [...]
– Bahaaaldin Mohammad
Jul 2 at 18:47






Yes, tileArray is basically your map one. You can make it so the numbers can represent different tile objects.
– Ramenous
Jul 2 at 19:30





ok thank you very much
– Bahaaaldin Mohammad
Jul 2 at 20:21





No problem! If this solves your issue, make sure to accept this as the answer since this is a common problem in javascript game dev. Thanks!
– Ramenous
Jul 2 at 21:19





ok so I added collision detection and everything worked very well, so I thought the next step was to make the map scroll and I did but.... the tile collision didnt work correctly any more it looked like when the map scrolled the drawing did but the collision detection didnt heres a hastpin link hastebin.com/adunogobiz.js
– Bahaaaldin Mohammad
2 days ago




<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}

canvas {
display: block;
margin: auto;
border: solid 1px white;
border-radius: 10px;
}

script {
display: none;
}
</style>
</head>

<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">

void function() {

"use strict";

// Classes
function Camera(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
}

Camera.prototype = {
set: function(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
},

pan: function(x,y) {
this.x += x || 0.0;
this.y += y || 0.0;
}
};

var nextID = 0;

function Tile(colour) {
this.id = nextID++;
this.colour = colour || "black";
}

function Map(width,height) {
this.width = width || 1;
this.height = height || 1;
this.map = ;
this.map.length = this.height;

for (var y = 0; y < this.height; ++y) {
this.map[y] = ;
this.map[y].length = width;

for (var x = 0; x < this.width; ++x) {
this.map[y][x] = Math.random() < 0.2 ?
this.TILE_WALL:
this.TILE_GRASS;
}

this.map[y][0] = this.TILE_WALL;
this.map[y][this.width - 1] = this.TILE_WALL;
}

for (var x = 0; x < this.width; ++x) {
this.map[0][x] = this.TILE_WALL;
this.map[this.height - 1][x] = this.TILE_WALL;
}
}

Map.prototype = {
TILE_WIDTH: 32.0,
TILE_HEIGHT: 32.0,
INV_TILE_WIDTH: 0.0,
INV_TILE_HEIGHT: 0.0,

TILE_AIR: new Tile("#00000000"),
TILE_GRASS: new Tile("#00AA00FF"),
TILE_WALL: new Tile("#555555FF"),

set: function(x,y,tile) {
this.map[y][x] = tile;
},

scaleX: function(x) {
return (x * this.INV_TILE_WIDTH) | 0;
},

scaleY: function(y) {
return (y * this.INV_TILE_HEIGHT) | 0;
},

isColliding: function(x,y) {
return x > -1 && x < this.width
&& y > -1 && y < this.height
&& this.map[y][x].id > 1;
},

render: function(ctx,camera) {
for (var y = 0; y < this.height; ++y) {
for (var x = 0; x < this.width; ++x) {
var tile = this.map[y][x];
var _x = x * this.TILE_WIDTH - camera.x;
var _y = y * this.TILE_HEIGHT - camera.y;

ctx.fillStyle = tile.colour;
ctx.fillRect(_x,_y,this.TILE_WIDTH - 1,this.TILE_HEIGHT - 1);
}
}
}
};

Map.prototype.INV_TILE_WIDTH = 1.0 / Map.prototype.TILE_WIDTH;
Map.prototype.INV_TILE_HEIGHT = 1.0 / Map.prototype.TILE_HEIGHT;

function Player(x,y) {
this.x = x || 0.0;
this.y = y || 0.0;
this.dx = 0.0;
this.dy = 0.0;
this.isUp = false;
this.isDown = false;
this.isLeft = false;
this.isRight = false;
}

Player.prototype = {
WIDTH: 20.0,
HEIGHT: 20.0,

ACCELERATION: 1.0,
DEACCELERATION: 0.5,
MAX_SPEED: 3.0,

tick: function(map) {
// Movement
if (this.isUp) {
this.dy -= this.ACCELERATION;

if (this.dy < -this.MAX_SPEED) {
this.dy = -this.MAX_SPEED;
}
} else if (this.dy < 0.0) {
this.dy += this.DEACCELERATION;

if (this.dy > 0.0) {
this.dy = 0.0;
}
}

if (this.isDown) {
this.dy += this.ACCELERATION;

if (this.dy > this.MAX_SPEED) {
this.dy = this.MAX_SPEED;
}
} else if (this.dy > 0.0) {
this.dy -= this.DEACCELERATION;

if (this.dy < 0.0) {
this.dy = 0.0;
}
}

if (this.isLeft) {
this.dx -= this.ACCELERATION;

if (this.dx < -this.MAX_SPEED) {
this.dx = -this.MAX_SPEED;
}
} else if (this.dx < 0.0) {
this.dx += this.DEACCELERATION;

if (this.dx > 0.0) {
this.dx = 0.0;
}
}

if (this.isRight) {
this.dx += this.ACCELERATION;

if (this.dx > this.MAX_SPEED) {
this.dx = this.MAX_SPEED;
}
} else if (this.dx > 0.0) {
this.dx -= this.DEACCELERATION;

if (this.dx < 0.0) {
this.dx = 0.0;
}
}

// Collision
if (this.dx !== 0.0) {
var minY = map.scaleY(this.y);
var maxY = map.scaleY(this.y + this.HEIGHT);
var minX = 0;
var maxX = 0;

if (this.dx < 0.0) {
minX = map.scaleX(this.x + this.dx);
maxX = map.scaleX(this.x);
} else {
minX = map.scaleX(this.x + this.WIDTH);
maxX = map.scaleX(this.x + this.WIDTH + this.dx);
}

loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.x = this.dx < 0.0 ?
(x + 1) * map.TILE_WIDTH:
x * map.TILE_WIDTH - this.WIDTH - 1;

this.dx = 0.0;
break loop;
}
}
}
}

if (this.dy !== 0.0) {
var minX = map.scaleX(this.x);
var maxX = map.scaleX(this.x + this.WIDTH);
var minY = 0;
var maxY = 0;

if (this.dy < 0.0) {
minY = map.scaleY(this.y + this.dy);
maxY = map.scaleY(this.y);
} else {
minY = map.scaleY(this.y + this.HEIGHT);
maxY = map.scaleY(this.y + this.HEIGHT + this.dy);
}

loop:
for (var y = minY; y <= maxY; ++y) {
for (var x = minX; x <= maxX; ++x) {
if (map.isColliding(x,y)) {
this.y = this.dy < 0.0 ?
(y + 1) * map.TILE_HEIGHT:
y * map.TILE_HEIGHT - this.HEIGHT - 1;

this.dy = 0.0;
break loop;
}
}
}
}

this.x += this.dx;
this.y += this.dy;
},

render: function(ctx,camera) {
camera.set(this.x,this.y);

ctx.lineWidth = 1;
ctx.strokeStyle = "black";
ctx.fillStyle = "darkred";
ctx.beginPath();
ctx.rect(this.x - camera.x,this.y - camera.y,this.WIDTH,this.HEIGHT);
ctx.fill();
ctx.stroke();
}
};

// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var camera = null;
var map = null;
var player = null;

// Functions
function onKeyDown(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = true; break;
case "S": player.isDown = true; break;
case "A": player.isLeft = true; break;
case "D": player.isRight = true; break;
}
}

function onKeyUp(e) {
switch(e.key.toUpperCase()) {
case "W": player.isUp = false; break;
case "S": player.isDown = false; break;
case "A": player.isLeft = false; break;
case "D": player.isRight = false; break;
}
}

function loop() {
// Tick
player.tick(map);

// Render
ctx.fillStyle = "gray";
ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);

map.render(ctx,camera);
player.render(ctx,camera);

//
requestAnimationFrame(loop);
}

// Entry point (first to execute)
onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;

ctx = canvas.getContext("2d");
ctx.translate(canvasWidth >> 1,canvasHeight >> 1);

camera = new Camera(0.0,0.0);
map = new Map(10,10);
player = new Player(40.0,40.0);

map.set(1,1,map.TILE_GRASS);

addEventListener("keydown",onKeyDown);
addEventListener("keyup",onKeyUp);

loop();
}

}();

</script>
</body>
</html>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

DW2 x9 zE0XmGnBalr DOtMPlYDpFKrjYhzfzNrY,mxJ 48L,cTBf6boP
CZ nKgmsHRatusAEIqucdbTdbakG,PBPR,lK QQuP OTffcq,k,cbt2 xd,znoHGb,K7j6xjClBSUz2znwU5c Znz zHa0d74nZdxM

Popular posts from this blog

Rothschild family

Boo (programming language)