Todor
Todor

Reputation: 67

Tile map collide not working as expected in Javascript

I have been thinking of a way to set-up tile map collision with a player in the same way I have developed the game so far (or similar way if possible, so I do not have to redo everything :) ).

I got some ideas from tutorials and videos and decided to implement it to my code and the player definitely collides with something, though it doesn't look to be the correct tiles that it should be.

For example I want it to walk on over the tiles with Index 1, but to collide with tiles with Index 0 and 3, to stop the player movement.

Here is what I got so far:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Canvas Tile Map</title>
        <style>
            #canvas{
                border: 1px solid black;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas" height="650px" width="1000px"></canvas>
        <script>

            var canvas = document.getElementById("canvas");
            var context = canvas.getContext("2d");

var go = 0;

var canvasBegX = -64;
var canvasEndX = 999;
var canvasBegY = -64;
var canvasEndY = 649;


var heroX = 0;      
var heroY = 0;      
var heroIndexX = 0;     
var heroIndexY = 0;     
var heroIndexXnew = 0;    
var heroIndexYnew = 0;

//--------------------------------------------------------------
            //ADD CHECKER IF KEY IS PRESSED OR RELEASED

        window.addEventListener('keydown', function (e) {
            canvas.key = e.keyCode;
        })
        window.addEventListener('keyup', function (e) {
            canvas.key = false;
        })

//--------------------------------------------------------------
                            //THE MAP
            var mapArray=[

        [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],
                [3,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,3],
                [3,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3],
                [3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,3],
                [3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3],
                [3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
                [3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
                [3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
                [3,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,3],
                [3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
                [3,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,3],
                [3,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,1,3],
                [3,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,3],
                [3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3],
        [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
            ];

// x= 22
// y= 15




//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
                  // DRAW PLAYER

  player_image = new Image();

var player = new Object();
player.y = canvas.height/2-220;    //player position y
player.x = canvas.width/2-340;     //player position x
player.Width = 60;
player.Height = 60;



function drawPlayer() {      // drawing the player
    context.beginPath();
    context.fillStyle = "red";
    context.fillRect(player.x,player.y,player.Width,player.Height);
    context.closePath();
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
                 // These I need for the map co-ordinates and when it moves the map upon key-press


      var updateX=(player.x-210);  // Starting point of canvas X
      var updateY=(player.y-160);  // Starting point of canvas Y
            var posX=updateX;
            var posY=updateY;




//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
       //DRAW THE MAP AND THE PLAYER      

var grass = new Image();
var stone = new Image();
var black = new Image();

function drawMap() {

var posY = updateY;    // new Y coordinates for the map after movement



            grass.src= 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/grass.jpeg';
            stone.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/sand.jpeg';
            black.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/black.png';

   //---------------------------------------------------------
                    // Draw the map loop
            grass.onload = function (){
            stone.onload = function (){
            black.onload = function (){
            for(var i=0; i < mapArray.length; i++){
                for(var j=0; j < mapArray[i].length; j++){





                    if(mapArray[i][j]==0){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
                        context.drawImage(grass,posX, posY, 64, 64);   // Load image for grass "0"
                           }
                    }



                    if(mapArray[i][j]==1){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
                        context.drawImage(stone,posX,posY,64,64);     // Load image for stone "1"
                           }
                    }



                    if(mapArray[i][j]==3){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
                        context.drawImage(black,posX,posY,64,64);     // Load image for black "3"
                           }
                    }





                    posX+=64;
                }
                posY+=64;
                posX=updateX;   // new X coordinates for the map after movement
   //---------------------------------------------------------
              drawPlayer();          // Draw the player
            }
        }
     }
    }
}


//-----------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------

                // PLAYER MOVEMENT BUTTONS

var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;

var endX=1408;
var endY=960;


document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
    if(e.keyCode == 39) {
       rightPressed = true;
    }
    else if(e.keyCode == 37) {
       leftPressed = true;
    }
    if(e.keyCode == 40) {
       downPressed = true;
    }
    else if(e.keyCode == 38) {
       upPressed = true;
    }
}
document.addEventListener("keyup", keyUpHandler);
function keyUpHandler(e) {
    if(e.keyCode == 39) {
       rightPressed = false;
    }
    else if(e.keyCode == 37) {
       leftPressed = false;
    }
    if(e.keyCode == 40) {
       downPressed = false;
    }
    else if(e.keyCode == 38) {
       upPressed = false;
    }
}


//----------------------------------------------
                //THE ACTUAL MOVEMENT + BOUNDARIES

function playerMovement(){
//------------------------------
               //CHECK PLAYER X AND Y IN TILE INDEXES

 heroX = Math.abs(updateX - player.x);   //current hero X position starting from beginning of tilemap(outside of visible part)
 heroY = Math.abs(updateY - player.y);   //current hero Y position starting from beginning of tilemap(outside of visible part)
 heroIndexX = heroX/64;   // X index of hero to chech in which tile is currently located
 heroIndexY = heroY/64;   // Y index of hero to chech in which tile is currently located
 heroIndexXnew = Math.ceil(heroIndexX);   //index positioned on the right of the heroes index
 heroIndexYnew = Math.ceil(heroIndexY) -2;   //index positioned on the left of the heroes index

    if(rightPressed) {

      if (isPathTile(mapArray, heroIndexXnew, heroIndexYnew)){             // Nothing happens because you hit a tile
            }else {
         moveRight();                 // if you are not at the wall, you go right
               }
    }
//------------------------------
    else if(leftPressed) {


         if (isPathTile(mapArray, heroIndexXnew - 2, heroIndexYnew)){             // Nothing happens because you hit a tile
            }else {
         moveLeft();                 // if you are not at the wall, you go left
               }
    }
//------------------------------
    if(downPressed) {
         if(player.y>updateY+834){}  // Nothing happens because you hit the bottom wall
       else {
         moveDown();                 // if you are not at the wall, you go down
               }
    }
//------------------------------
    else if(upPressed) {
         if(player.y<updateY+64){}  // Nothing happens because you hit the top wall
       else {
         moveUp();                   // if you are not at the wall, you go up
               }
    }
}



//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
            //CAMERA BOUNDARIES 
function moveRight(){
 if(player.x<820){
  player.x=player.x+4.1;     //If you are at this position, move the player
 }
 else if(player.x>820){
  updateX=updateX-4.1;       //If you go over this position, move the background
 }
}

function moveLeft(){
 if(player.x>100){
  player.x=player.x-4.1;     //If you are at this position, move the player
 }
 else if(player.x<100){
  updateX=updateX+4.1;       //If you go over this position, move the background
 }
}

function moveUp(){
 if(player.y>80){
  player.y=player.y-4.1;     //If you are at this position, move the player
 }
 else if(player.y<80){
  updateY=updateY+4.1;       //If you go over this position, move the background
 }
}

function moveDown(){
 if(player.y<500){
  player.y=player.y+4.1;     //If you are at this position, move the player
 }
 else if(player.y>500){
  updateY=updateY-4.1;       //If you go over this position, move the background
 }
}



//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------



//------------------------------------------------------------------------------------------------------
               // MOVEMENT BOUNDARIES WITH TILES 
function isPathTile(mapArray, x, y) {
    return (mapArray[x][y] === 0); // Because 0 is the path tile
}

//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
                // THE GAME LOOP 

function gameLoop(){

console.log("index X =" + heroIndexXnew);
console.log("index Y =" + heroIndexYnew);
playerMovement();          //Check for movements
drawMap();                 //Draw the map and the player



requestAnimationFrame(gameLoop);
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------



gameLoop();   // start the gameLoop

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

And here is a code to test it -

			var canvas = document.getElementById("canvas");
			var context = canvas.getContext("2d");

var go = 0;

var canvasBegX = -64;
var canvasEndX = 999;
var canvasBegY = -64;
var canvasEndY = 649;


var heroX = 0;      
var heroY = 0;      
var heroIndexX = 0;     
var heroIndexY = 0;     
var heroIndexXnew = 0;    
var heroIndexYnew = 0;

//--------------------------------------------------------------
            //ADD CHECKER IF KEY IS PRESSED OR RELEASED

        window.addEventListener('keydown', function (e) {
            canvas.key = e.keyCode;
        })
        window.addEventListener('keyup', function (e) {
            canvas.key = false;
        })
			
//--------------------------------------------------------------
                            //THE MAP
			var mapArray=[

        [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],
				[3,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,3],
				[3,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3],
				[3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,3],
				[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3],
				[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
				[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
				[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
				[3,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,3],
				[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
				[3,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,3],
				[3,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,1,3],
				[3,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,3],
				[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3],
        [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
			];

// x= 22
// y= 15




//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
                  // DRAW PLAYER

  player_image = new Image();

var player = new Object();
player.y = canvas.height/2-220;    //player position y
player.x = canvas.width/2-340;     //player position x
player.Width = 60;
player.Height = 60;



function drawPlayer() {      // drawing the player
    context.beginPath();
    context.fillStyle = "red";
    context.fillRect(player.x,player.y,player.Width,player.Height);
    context.closePath();
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
                 // These I need for the map co-ordinates and when it moves the map upon key-press
			

      var updateX=(player.x-210);  // Starting point of canvas X
      var updateY=(player.y-160);  // Starting point of canvas Y
			var posX=updateX;
			var posY=updateY;




//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
       //DRAW THE MAP AND THE PLAYER      

var grass = new Image();
var stone = new Image();
var black = new Image();

function drawMap() {

var posY = updateY;    // new Y coordinates for the map after movement



			grass.src= 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/grass.jpeg';
			stone.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/sand.jpeg';
			black.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/black.png';

   //---------------------------------------------------------
                    // Draw the map loop
			grass.onload = function (){
			stone.onload = function (){
			black.onload = function (){
			for(var i=0; i < mapArray.length; i++){
				for(var j=0; j < mapArray[i].length; j++){


        


					if(mapArray[i][j]==0){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
						context.drawImage(grass,posX, posY, 64, 64);   // Load image for grass "0"
						   }
					}



					if(mapArray[i][j]==1){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
						context.drawImage(stone,posX,posY,64,64);     // Load image for stone "1"
						   }
					}



					if(mapArray[i][j]==3){
               if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
						context.drawImage(black,posX,posY,64,64);     // Load image for black "3"
						   }
					}


				


					posX+=64;
				}
				posY+=64;
				posX=updateX;   // new X coordinates for the map after movement
   //---------------------------------------------------------
              drawPlayer();          // Draw the player
			}
		}
	 }
	}
}


//-----------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------

                // PLAYER MOVEMENT BUTTONS

var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;

var endX=1408;
var endY=960;


document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
    if(e.keyCode == 39) {
       rightPressed = true;
    }
    else if(e.keyCode == 37) {
       leftPressed = true;
    }
    if(e.keyCode == 40) {
       downPressed = true;
    }
    else if(e.keyCode == 38) {
       upPressed = true;
    }
}
document.addEventListener("keyup", keyUpHandler);
function keyUpHandler(e) {
    if(e.keyCode == 39) {
       rightPressed = false;
    }
    else if(e.keyCode == 37) {
       leftPressed = false;
    }
    if(e.keyCode == 40) {
       downPressed = false;
    }
    else if(e.keyCode == 38) {
       upPressed = false;
    }
}


//----------------------------------------------
                //THE ACTUAL MOVEMENT + BOUNDARIES

function playerMovement(){
//------------------------------
               //CHECK PLAYER X AND Y IN TILE INDEXES

 heroX = Math.abs(updateX - player.x);   //current hero X position starting from beginning of tilemap(outside of visible part)
 heroY = Math.abs(updateY - player.y);   //current hero Y position starting from beginning of tilemap(outside of visible part)
 heroIndexX = heroX/64;   // X index of hero to chech in which tile is currently located
 heroIndexY = heroY/64;   // Y index of hero to chech in which tile is currently located
 heroIndexXnew = Math.ceil(heroIndexX);   //index positioned on the right of the heroes index
 heroIndexYnew = Math.ceil(heroIndexY) -2;   //index positioned on the left of the heroes index

    if(rightPressed) {

      if (isPathTile(mapArray, heroIndexXnew, heroIndexYnew)){             // Nothing happens because you hit a tile
			}else {
         moveRight();                 // if you are not at the wall, you go right
			   }
    }
//------------------------------
    else if(leftPressed) {


         if (isPathTile(mapArray, heroIndexXnew - 2, heroIndexYnew)){             // Nothing happens because you hit a tile
			}else {
         moveLeft();                 // if you are not at the wall, you go left
			   }
    }
//------------------------------
    if(downPressed) {
         if(player.y>updateY+834){}  // Nothing happens because you hit the bottom wall
       else {
         moveDown();                 // if you are not at the wall, you go down
			   }
    }
//------------------------------
    else if(upPressed) {
         if(player.y<updateY+64){}  // Nothing happens because you hit the top wall
       else {
         moveUp();                   // if you are not at the wall, you go up
			   }
    }
}



//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
            //CAMERA BOUNDARIES 
function moveRight(){
 if(player.x<820){
  player.x=player.x+4.1;     //If you are at this position, move the player
 }
 else if(player.x>820){
  updateX=updateX-4.1;       //If you go over this position, move the background
 }
}

function moveLeft(){
 if(player.x>100){
  player.x=player.x-4.1;     //If you are at this position, move the player
 }
 else if(player.x<100){
  updateX=updateX+4.1;       //If you go over this position, move the background
 }
}

function moveUp(){
 if(player.y>80){
  player.y=player.y-4.1;     //If you are at this position, move the player
 }
 else if(player.y<80){
  updateY=updateY+4.1;       //If you go over this position, move the background
 }
}

function moveDown(){
 if(player.y<500){
  player.y=player.y+4.1;     //If you are at this position, move the player
 }
 else if(player.y>500){
  updateY=updateY-4.1;       //If you go over this position, move the background
 }
}



//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------



//------------------------------------------------------------------------------------------------------
               // MOVEMENT BOUNDARIES WITH TILES 
function isPathTile(mapArray, x, y) {
    return (mapArray[x][y] === 0); // Because 0 is the path tile
}

//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
                // THE GAME LOOP 

function gameLoop(){

console.log("index X =" + heroIndexXnew);
console.log("index Y =" + heroIndexYnew);
playerMovement();          //Check for movements
drawMap();                 //Draw the map and the player



requestAnimationFrame(gameLoop);
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------



gameLoop();   // start the gameLoop
			#canvas{
				border: 1px solid black;
			}
<canvas id="canvas" height="650px" width="1000px"></canvas>

All the code has some vars, the tilemap array, drawing the tilemap in only the visible part of the canvas , the player of course with it for every time it draws, then we have the movement and where I believe something is not set correctly. There is a function isPathTile to see if the index next to the current player location is 0 and if it is, it does nothing (when right pressed, so the player does not move). I think that this is where I got it wrong. Much appreciated if anyone can take can a look at this.

Upvotes: 0

Views: 569

Answers (2)

Todor
Todor

Reputation: 67

After about a week was giving up on this one :D and finally figured it out. I was switching the places of my X and Y indexes and that is why it was not acting as it should be. Showing up the fix here if anyone is interested (only the Player movement has to be updated):

function playerMovement(){
//------------------------------
               //CHECK PLAYER X AND Y IN TILE INDEXES
 heroX = -updateX + player.x;
 heroY = -updateY + player.y;
 heroIndexX = heroX/64;   // get the X index
 heroIndexY = heroY/64;   // get the Y index
 heroIndexXnew = Math.ceil(heroIndexX);
 heroIndexYnew = Math.ceil(heroIndexY);

    if(rightPressed) {
          player_image.src = './images/horseright1.png';



         if(player.x>updateX+1258){  // Nothing happens because you hit the right wall
            }else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew)){             // Nothing happens because you hit a tile
            }else {
         moveRight();                 // if you are not at the wall, you go right
               }
    }
//------------------------------
    else if(leftPressed) {
          player_image.src = './images/horseleft1.png';


         if(player.x<updateX+128){  // Nothing happens because you hit the left wall
            }else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew - 1)){             // Nothing happens because you hit a tile
            }else {
         moveLeft();                 // if you are not at the wall, you go left
               }
    }
//------------------------------
    if(downPressed) {
         if(player.y>updateY+834){  // Nothing happens because you hit the bottom wall
            }else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew)){             // Nothing happens because you hit a tile
            }else {
         moveDown();                 // if you are not at the wall, you go down
               }
    }
//------------------------------
    else if(upPressed) {
         if(player.y<updateY+64){  // Nothing happens because you hit the top wall
            }else if (isPathTile(mapArray, heroIndexYnew - 1, heroIndexXnew)){             // Nothing happens because you hit a tile
            }else {
         moveUp();                   // if you are not at the wall, you go up
               }
    }
}

A simple mistake and took me one hell of a time for debugging, though the logic is good and simple. Needs a bit of a touch on how it collides exactly as there are few things to be updated, but overall it works great!

Upvotes: 0

Mr. Reddy
Mr. Reddy

Reputation: 1114

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				position: absolute;
				margin: auto;
				left: 0;
				right: 0;
				border: solid 1px white;
			}
		</style>
	</head>
	
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
		
		// IIFE
		// https://developer.mozilla.org/en-US/docs/Glossary/IIFE
		void function() {
			
			// Enforce strict mode inside the IIFE
			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
			"use strict";
			
			// Var declaration
			var canvasWidth = 320;
			var canvasHeight = 320;
			var canvas = null;
			var ctx = null;
			var player = {
				// Position
				x: 35.0,
				y: 35.0,
				
				// Velocity
				dx: 0.0,
				dy: 0.0,
				
				// Size
				width: 20,
				height: 20,
				
				// Input
				up: false,
				down: false,
				left: false,
				right: false
			};
			
			// Defined this way the map will need to be indexed as
			// map[y][x]
			// 0 = not solid
			// 1 = solid
			var mapTileSize = 32; // size for each tile in pixels
			var map = [
				[1,1,1,1,1,1,1,1,1,1],
				[1,0,1,0,0,0,0,0,1,1],
				[1,0,0,1,1,1,0,1,0,1],
				[1,0,0,0,0,0,0,0,0,1],
				[1,0,0,0,0,0,0,0,0,1],
				[1,0,0,0,0,0,0,0,0,1],
				[1,0,1,1,1,1,0,1,0,1],
				[1,0,0,0,0,0,0,1,0,1],
				[1,0,0,0,0,0,0,0,0,1],
				[1,1,1,1,1,1,1,1,1,1]
			];
			
			// Runs after the page has finished loading
			window.onload = function() {
				canvas = document.getElementById("canvas");
				canvas.width = canvasWidth;
				canvas.height = canvasHeight;
				ctx = canvas.getContext("2d");
				
				loop();
			}
			
			// Key Input
			window.onkeydown = function(e) {
				switch(e.key) {
					case "w": player.up = true; break;
					case "s": player.down = true; break;
					case "a": player.left = true; break;
					case "d": player.right = true; break;
				}
			}
			
			window.onkeyup = function(e) {
				switch(e.key) {
					case "w": player.up = false; break;
					case "s": player.down = false; break;
					case "a": player.left = false; break;
					case "d": player.right = false; break;
				}
			}
			
			function loop() {
				// Tick
				
				// Player movement
				if (player.up) {
					player.dy = -2;
				}
				
				if (player.down) {
					player.dy = +2;
				}
				
				if (!player.up && !player.down) {
					player.dy = 0;
				}
				
				if (player.left) {
					player.dx = -2;
				}
				
				if (player.right) {
					player.dx = +2;
				}
				
				if (!player.left && !player.right) {
					player.dx = 0;
				}
				
				// Collision detection & resolution
				
				// Only perform collision detection in either axis
				// if the player is actually moving on that axis
				
				// Map grid coordinates at the corners of the player's bounding box
				/*
					-> *-----* <-
					   |     |
					   |     |
					   |     |
					-> *-----* <-
				*/
				var invMapTileSize = 1.0 / mapTileSize;
				var nextX = player.x + player.dx;
				var nextY = player.y + player.dy;
				
				// Current position
				var currentMinX = (player.x * invMapTileSize) | 0;
				var currentMaxX = ((player.x + player.width) * invMapTileSize) | 0;
				var currentMinY = (player.y * invMapTileSize) | 0;
				var currentMaxY = ((player.y + player.height) * invMapTileSize) | 0;
				
				// Next position
				var nextMinX = (nextX * invMapTileSize) | 0;
				var nextMaxX = ((nextX + player.width) * invMapTileSize) | 0;
				var nextMinY = (nextY * invMapTileSize) | 0;
				var nextMaxY = ((nextY + player.height) * invMapTileSize) | 0;
				
				/*
					Collision checks are performed down along each axis of the player's
					collision box, this way it won't matter if the player is larger
					or smaller then the map tiles.
				*/
				
				// X axis collision
				if (player.dx !== 0.0) {
					for (var x = nextMinX; x <= nextMaxX; ++x) {
						for (var y = currentMinY; y <= currentMaxY; ++y) {
							if (map[y][x]) {
								player.dx = 0.0;
								break;
							}
						}
					}
				}
				
				// Y axis collision
				if (player.dy !== 0.0) {
					for (var y = nextMinY; y <= nextMaxY; ++y) {
						for (var x = currentMinX; x <= currentMaxX; ++x) {
							if (map[y][x]) {
								player.dy = 0.0;
								break;
							}
						}
					}
				}
				
				// Update player position
				player.x = player.x + player.dx;
				player.y = player.y + player.dy;
				
				// render
				ctx.fillStyle = "gray";
				ctx.fillRect(0,0,canvasWidth,canvasHeight);
				
				// draw map
				ctx.fillStyle = "darkred";
				ctx.beginPath();
				
				for (var y = 0; y < map.length; ++y) {
					for (var x = 0; x < map[0].length; ++x) {
						if (map[y][x]) {
							ctx.rect(
								x * mapTileSize,
								y * mapTileSize,
								mapTileSize,
								mapTileSize
							);
						}
					}
				}
				
				ctx.fill();
				
				// draw player
				ctx.fillStyle = "darkblue";
				ctx.fillRect(
					player.x,
					player.y,
					player.width,
					player.height
				);
				
				//
				requestAnimationFrame(loop);
			}
			
		}();
		
		</script>
	</body>
</html>

Upvotes: 1

Related Questions