title: 2D Tile map collision detection - player automaticly moves down
body: <p>I have a simple 2d tile map game but I'm trying to get the collision detection to work. When the player bumps into the floor or ceiling it seems fine but when the player bumps into the wall, they zoom down very fast and I'm not sure why. Here is a jsfiddle of the code - <a href="https://jsfiddle.net/o6dn1z6u/3/" rel="nofollow noreferrer">https://jsfiddle.net/o6dn1z6u/3/</a></p>
  
  <p>I've made it so that the game checks every tile that the player is in (max 4). Here is the code if the jsfiddle is too messy</p>
  
  <p>Declaring the tile map. 0's are transparent, everything else will be a wall/ floor etc:</p>
  
  <pre><code>    var levelOne = {
      background: 'lightblue',
      collisions: [
          [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,1],
          [1,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,1],
          [1,0,0,0,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
          [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
      ],
      player: {spawnX: 1, spawnY: 18}
  }
  </code></pre>
  
  <p>Standard game variables: </p>
  
  <pre><code>    var canvas = document.getElementById('game-canvas');
  var context = canvas.getContext('2d');
  
  var tile = 40;
  var FPS = 30;
  var currentLevel = levelOne;
  
  var playerLeft = false;
  var playerRight = false;
  var playerUp = false;
  var playerDown = false;
  var speed = 6;
  var xSpeed = 0;
  var ySpeed = 0;
  
  var playerX = currentLevel.player.spawnX * tile; 
  var playerY = currentLevel.player.spawnY * tile; 
  
  function draw()
  {
      updateMap(currentLevel);
      updatePlayer(currentLevel.player);
  }
  
  setInterval(draw, 1000/ FPS);
  </code></pre>
  
  <p>Updating the map is just drawing the tiles to the canvas so I'll skip that. When updating the player it gets the move the player wants to do, if the new move would collide with a wall, it will position them right next to the wall so if they player is at X: 2 and they move 5 spaces down, it will position them at x:0 instead of leaving them at x: 2</p>
  
  <pre><code>    function updatePlayer (player)
  {
      var newX = playerX;
      var newY = playerY; 
  
      if (playerLeft)
      {
          newX -= speed;
      }
  
      if (playerRight)
      {
          newX += speed;
      }
  
      if (playerUp)
      {
          newY -= speed;
      }
  
      if (playerDown)
      {
          newY += speed;
      }
      if (!verticleCollision(newX, newY))
      {
          playerY = newY;
      }
      else
      {
          newY = playerY;
      }
  
      if (!horizontalCollision(newX, newY))
      {
          playerX = newX;
      }
  
      context.fillStyle = 'blue';
      context.fillRect(playerX, playerY, tile, tile);
  }
  </code></pre>
  
  <p>Here are the collision functions. I wanted to make 2 for horizontal and vertical so you could effectively slide on the floor or wall. On the fiddle I have colored in the 4 boxes that the player is on, so I could visualize the collision.</p>
  
  <pre><code>    function verticleCollision(x, y)
  {
      var topLeftX = Math.floor(x/tile);
      var topLeftY = Math.floor(y/tile);
  
      var bottomLeftX = Math.floor(x/tile)
      var bottomLeftY = Math.ceil(y/tile);
  
      var topRightX = Math.ceil(x/tile);
      var topRightY = Math.floor(y/tile);
  
      var bottomRightX = Math.ceil(x/tile);
      var bottomRightY = Math.ceil(y/tile);
  
      if ((currentLevel.collisions[topLeftY][topLeftX] != 0) || (currentLevel.collisions[topRightY][topRightX] != 0))
      {
          playerY = topLeftY * tile + tile;
          return true;
      }
      else if ((currentLevel.collisions[bottomLeftY][bottomLeftX] != 0) || (currentLevel.collisions[bottomRightY][bottomRightX] != 0))
      {
          playerY = bottomLeftY * tile - tile;
          return true;
      }
      else
      {
          return false;
      }
  }
  
  function horizontalCollision(x, y)
  {
      var topLeftX = Math.floor(x/tile);
      var topLeftY = Math.floor(y/tile);
  
      var bottomLeftX = Math.floor(x/tile)
      var bottomLeftY = Math.ceil(y/tile);
  
      var topRightX = Math.ceil(x/tile);
      var topRightY = Math.floor(y/tile);
  
      var bottomRightX = Math.ceil(x/tile);
      var bottomRightY = Math.ceil(y/tile);
  
      if ((currentLevel.collisions[topLeftY][topLeftX] != 0) || (currentLevel.collisions[bottomLeftY][bottomLeftX] != 0))
      {
          playerX = topLeftX * tile + tile;
          return true;
      }
      else if ((currentLevel.collisions[bottomRightY][bottomRightX] != 0) || (currentLevel.collisions[bottomLeftY][bottomLeftX] != 0))
      {
          playerX = bottomRightX * tile - tile;
          return true;
      }
      else
      {
          return false;
      }
  }
  </code></pre>
  
  <p>There is quite a lot of code which is why I included the jsfiddle but any help is appreciated :)</p>