I've been working on a tile based game with a 2d array as fundamental ground for my tiles. Now my next step is to have the wall tiles be impenetrable, so that the player can walk ontop of them and collide against their sides/bottom.
So as this is loosely based on tonyPa tutorial, it uses the corners of the player character (top-left, top-right, bottom-left, bottom-right corners) to check if any corner hits a wall (walls are assigned as "1" in the 2d array). When a corner touches a tile that is recognized as "1" (wall), I want to check from what side the player is hitting, and then move the player next to the tiles side, to simulate a collision.
Now what I've noticed is, it's easy to check if any corner is touching a wall, but its harder to determine which side the corner is hitting. Because of this, my current code is not simulating a satisfying collision detection. As my hero walks on the ground, he randomly stops because the bottom corners not only touch the top of the tiles, but also the sides it seems.
UPDATE
So I changed my code based on the first answer by bummzack. Using center points of each side of player entity instead of each corner. And now my character slides down walls without getting stuck and walks across grounds fairly smoothly, but another problem arises. If the player jumps on a tile, and the center part of the bottom is NOT within the tiles width, he falls right through. And this is because I am just comparing a POINT (the center point specifically) and not the full bottom side against the top of the tile beneath the player.
Here's a link to the SWF-file, http://dl.dropbox.com/u/28271061/_TileGameFLA.swf , X to JUMP, Z to RUN, ARROWKEYS to MOVE, which should give you a visual example of what's happening:
Here is the UPDATED code (all collision code is within "collisionCheck" function)
private function onKEYDOWN(event:KeyboardEvent):void{
var pressedKey = event.keyCode;
if(pressedKey == Keyboard.RIGHT){
rightKey = true;
}
if(pressedKey == Keyboard.LEFT){
leftKey = true;
}
if(pressedKey == Keyboard.Z){
runKey = true;
}
if(pressedKey == Keyboard.X){
jumpKey = true;
}
}
private function onKEYUP(event:KeyboardEvent):void{
var releasedKey = event.keyCode;
if(releasedKey == Keyboard.RIGHT){
rightKey = false;
}
if(releasedKey == Keyboard.LEFT){
leftKey = false;
}
if(releasedKey == Keyboard.Z){
runKey = false;
}
if(releasedKey == Keyboard.X){
jumpKey = false;
}
}
private function collisionCheck():void{
centerY = Math.floor((theHero.y + (theHero.width/2))/ts);
centerX = Math.floor((theHero.x + (theHero.width/2))/ts);
top = Math.floor(theHero.y / ts);
bottom = Math.floor((theHero.y + theHero.height) / ts);
left = Math.floor(theHero.x / ts);
right = Math.floor((theHero.x + theHero.width) / ts);
//If there is no ground under the player, start falling.
if(curMap[bottom][centerX] != 1 && curMap[bottom][centerX] != 1){
gravity = 3;
onGround = false;
}
if(vy > 0 && oldBottom < bottom){
if(curMap[bottom][centerX] != 0){//If either on of the bottom corners are touching a "1"-tile (a wall)
theHero.y = ((bottom - 1) * ts) + 2 ;
gravity = 0;
vy = 0;
onGround = true;
jumped = false;
jumpSpeed = 9;
}
}
if(vy < 0 && oldTop > top){
if(curMap[top][centerX] != 0){
theHero.y = (top + 1) * ts;
gravity = 3;
vy = 0;
jumpSpeed = 0;
}
}
if(vx < 0 && oldLeft > left ){
if(curMap[centerY][left] != 0){
vx = 0;
theHero.x = (left + 1) * ts;
}
}
trace(curMap[bottom][centerX]);
if(vx > 0 && oldRight < right ){
if(curMap[centerY][right] != 0 ){
vx = 0;
theHero.x = ((right - 1) * ts )+ 1.8; // 1.8 so it doesnt touch wall, it goes right through if its the accurate 2.0
}
}
}
private function moveChar():void{
if(rightKey){
if(runKey){
vx = 7;
}else{
vx = 4;
}
}
if(leftKey){
if(runKey){
vx = -7;
}else{
vx = -4;
}
}
//Stand still if you're not pressing left or right ON THE GROUND (in air you should after one key press)
if(!leftKey && !rightKey && onGround){
vx = 0;
}
if(jumpKey && jumpSpeed > 1 && !jumped){
vy -= jumpSpeed;
jumpSpeed *= 0.8;
onGround = false;
gravity = 3;
}
vy += gravity;
if(vy > 14){
vy = 14;
}
}
private function onENTERFRAME(event:Event):void{
if(myStage.stage.focus != myStage){
myStage.stage.focus = myStage;
}
//These variables represent where the hero WAS before being moved
//, this helps to see if hero approached the tile from the left/right/top/bottom
//, thus gives us an additional way to check where player is coming from
oldBottom = Math.floor((theHero.y + theHero.height) / ts);
oldLeft = Math.floor(theHero.x / ts);
oldRight = Math.floor(theHero.x + theHero.width) / ts;
oldTop = Math.floor(theHero.y / ts);
moveChar();
theHero.y += vy;
theHero.x += vx;
collisionCheck();
}
}
}
This is by far not the smartest way to check collisons, but I think it might work well enough. I just need someone to throw me in the right direction for making a solid collision detection engine for a simple tile based game.