HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

2D tilemap collision method

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
tilemapcollisionmethod

Problem

Is this the optimal method to check for collisions in a 2d-based game? I put together a working demo of 2D collisions here (WSAD to move, orange blocks collide).

I currently use the following code to check for collisions:

function checkmove(x, y) {
  if(level[Math.floor(x/20)][Math.floor(y/20)] == 1 || level[Math.ceil(x/20)][Math.floor(y/20)] == 1 || level[Math.floor(x/20)][Math.ceil(y/20)] == 1 || level[Math.ceil(x/20)][Math.ceil(y/20)] == 1) {
    return false;
  } else {
    return true;
  }
}


Update function:

function update(key) {
  switch(key) {
    case "W":
      if(checkmove(pos.x, pos.y-2)) {
        pos.y -= 2;
        break;
      } else {
        break;
      } 
    case "S":
      if(checkmove(pos.x, pos.y+2)) {
      pos.y += 2;
        break;
      } else {
        break;
      }
    case "A":
      if(checkmove(pos.x-2, pos.y)) {
      pos.x -= 2;
      break;
      } else {
        break;
      }
    case "D":
      if(checkmove(pos.x+2, pos.y)) {
      pos.x += 2;
       break;
      } else {
        break;
      }
    default:
      break;
  }
}


This is called before movement is applied the the 'player'. The game is laid out as a 2D array of 1's and 0's for testing purposes.

Can I use fewer mathematical operations (less expensive for each tick) to check for a collision between the player and a '1' on my game grid?

Solution

Before making this more efficient I'd suggest making it more readable:

in your switch statement you have break in both the true and else parts of your if statement.

if(checkmove(pos.x, pos.y-2)) {
    pos.y -= 2;
    break;
} else {
    break;
}


It would be much easier to read if you just move the break out of the if statement.

if(checkmove(pos.x, pos.y-2)) {
    pos.y -= 2;
}
break;


In another question I had suggested a bit shaving optimisation that might help here. Math.floor(number) is equivalent to number >> 0 this bit shifts the number by 0 bits and converts it to an integer.

Math.floor(x/20)


becomes

(x / 20) >> 0


similarly adding almost 1 (+ 1 - Number.EPSILON) and then flooring will give you the ceiling. (number + 1 - Number.EPSILON) >> 0

The checkmove() function calculates this multiple times on the one line. I'd rewrite it to calculate once.

function checkmove(x, y) {
  var floorX = (x/20) >> 0;
  var floorY = (y/20) >> 0;
  var ceilX = ((x/20) + 1 - Number.EPSILON) >> 0;
  var ceilY = ((y/20) + 1 - Number.EPSILON) >> 0;

  return level[floorX][floorY] == 1 ||
      level[ceilX][floorY] == 1 ||
      level[floorX][ceilY] == 1 ||
      level[ceilX][ceilY] == 1;
}

Code Snippets

if(checkmove(pos.x, pos.y-2)) {
    pos.y -= 2;
    break;
} else {
    break;
}
if(checkmove(pos.x, pos.y-2)) {
    pos.y -= 2;
}
break;
Math.floor(x/20)
(x / 20) >> 0
function checkmove(x, y) {
  var floorX = (x/20) >> 0;
  var floorY = (y/20) >> 0;
  var ceilX = ((x/20) + 1 - Number.EPSILON) >> 0;
  var ceilY = ((y/20) + 1 - Number.EPSILON) >> 0;

  return level[floorX][floorY] == 1 ||
      level[ceilX][floorY] == 1 ||
      level[floorX][ceilY] == 1 ||
      level[ceilX][ceilY] == 1;
}

Context

StackExchange Code Review Q#60439, answer score: 8

Revisions (0)

No revisions yet.