I make a small game with Javascript and Canvas. I have an collision detection but it works not so well. I cant go through walls. So far so good, but it works only on the left and top without overlap.
My map is array based with 0 and 1. 1 is walkable, 0 has to block
My player is 32x32 and my tiles too.
PosX is x Coordinate from may Player PosY is y Coordinate from may Player
Here is my detection Code:
var tileWidth = 32; // Fliesen breite festgelegt
var tileHeight = 32; // Fliesen höhe festgelegt
var solidTiles = [0]; // var solidTiles beinhaltet die 0 aus dem array, sagt das die nicht durchdringbar sein sollen (Hol mir quasi die 0 ausem array raus
function isSolidTile(x, y) { // Funktion zu festlegung das 0 Fließen nicht durchgehbar sind, x Pixel und y Pixel der fliese
var tileX = Math.floor(x / tileWidth); // Fließe in X --> x koordinate / durch die halbe breite, damit wir den mittelpunkt der fliese als festen punkt feststellen
var tileY = Math.floor(y / tileHeight); // Fließe in Y --> y koordinate / durch die halbe breite, damit wir den mittelpunkt der fliese als festen punkt feststellen
var tile = mapKollision[ tileY ][tileX] ; // WICHTIG!: Bei Listen ist auch die Zeile und Spalte einzuhalten. Bei der Abfrage einer Kollision zu erst Y dann X
if ( tile == 0 ) { //
return true; //
} else {return false} //
}
var altPosX = PosX; // neue variable für die alte helden position
var altPosY = PosY;
if ( isSolidTile( PosX, PosY) ){ // if wenn isSolidTile getroffen wird
PosX = altPosX; // soll er DIESE PosX in die alte Pos X umwandeln
PosY = altPosY; // soll er DIESE PosY in die alte Pos Y umwandeln
}
I know i have to say something like
if( PosX + 32 ) PosX = altPosX -32;
But when i use this, my player bounced back from the right side of the Blocking Tile, and when i go left, my player got through all the blocking tiles left from my player.
But what i want is, that when my player touches with his right side of his 32x32 the left side of an blocking Tile, he has to stop.
And i dont know why it doesn`t work.
If you need more Code, please let me know.
Thanks :)
From what I see I assume your collision detection is just based on a single point of the player sprite - most likely it's center point. To make a more precise collision detection, we need to account for the corner points surrounding that object and the direction it's moving to. Additionally we need to check if we would collide with a solid object like a wall before we actually move it to that position. That way we can place it side-by-side to that object.
Consider this example:
Our player sprite is the red square and it's moving at 4 pixels per frame. A you can see the sprite and the blue wall are just 2 pixels apart! If we move to the right by 4 pixels, the bottom right hits the wall.
To get around that problem we need to check the sprite's top-right and bottom-right corners for a possible collision if we want to move to the right.
If we detect a collision - again, before we actually moved something on screen - we put the red hero next to the block instead.
Heres a sophisticated example. Give it focus by a mouse click and use the cursor keys to move around.
var whichKey = 0; var tileWidth = 32; var tileHeight = 32; var player = { tileX: 2, tileY: 2, xPos: 0, yPos: 0, speed: 3, width: 24, height: 24, topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0 }; player.xPos = player.tileX * tileWidth + tileWidth / 2 - player.width / 2; player.yPos = player.tileY * tileHeight + tileHeight / 2 - player.height / 2; var map = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ]; var canvas = document.createElement("canvas"); canvas.width = 400; canvas.height = 300; var context = canvas.getContext("2d"); document.body.appendChild(canvas); function updateMap() { context.clearRect(0, 0, canvas.width, canvas.height); context.fillStyle = "black"; for (var a = 0; a < map.length; a++) { for (var b = 0; b < map[0].length; b++) { if (map[a][b] == 1) { context.fillRect(b * tileWidth, a * tileHeight, tileWidth, tileHeight); } } } context.fillStyle = "red"; context.fillRect(player.xPos, player.yPos, player.width, player.height); player.tileX = Math.floor(player.xPos / tileWidth); player.tileY = Math.floor(player.yPos / tileHeight); } function getCorners(futureX, futureY) { var bottom = Math.floor((futureY + player.height - 1) / tileHeight); var top = Math.floor((futureY) / tileHeight); var left = Math.floor((futureX) / tileWidth); var right = Math.floor((futureX + player.width - 1) / tileWidth); player.topLeft = map[top][left]; player.topRight = map[top][right]; player.bottomLeft = map[bottom][left]; player.bottomRight = map[bottom][right]; } function move(directionX, directionY) { getCorners(player.xPos + player.speed * directionX, player.yPos); if (directionX == -1) { if (player.topLeft == 0 && player.bottomLeft == 0) { player.xPos += player.speed * directionX; } else { player.xPos = player.tileX * tileWidth; } } if (directionX == 1) { if (player.topRight == 0 && player.bottomRight == 0) { player.xPos += player.speed * directionX; } else { player.xPos = (player.tileX + 1) * tileWidth - player.width; } } getCorners(player.xPos, player.yPos + player.speed * directionY); if (directionY == -1) { if (player.topLeft == 0 && player.topRight == 0) { player.yPos += player.speed * directionY; } else { player.yPos = player.tileY * tileHeight; } } if (directionY == 1) { if (player.bottomLeft == 0 && player.bottomRight == 0) { player.yPos += player.speed * directionY; } else { player.yPos = (player.tileY + 1) * tileHeight - player.height; } } } window.addEventListener('keydown', function(e) { whichKey = e.keyCode; }); window.addEventListener('keyup', function(e) { whichKey = 0; }); function loop() { if (whichKey == 37) { move(-1, 0); } if (whichKey == 39) { move(1, 0); } if (whichKey == 38) { move(0, -1); } if (whichKey == 40) { move(0, 1); } updateMap(); } var interval = setInterval(loop, 20);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.