I'm pretty new to Game Development and am just learning mostly theory and simple physics by developing a HTML5 Canvas Game before moving on to other languages (Being a Web Developer all I had to learn was the Canvas API).
I'm having some issues with my Collision Detection/Correction. To put it simply, here is a run down of what happens to the Player Entity in every loop:
- Apply the physics to a temporary X and Y Co-ordinates to find the new position of the Player (E.g. Friction and Gravity)
- Generate points around the sprite to check for collisions and assign them directions (Which allows for collision correction based on the direction of the collision)
- Loop through each of the points, find the Tile each point is on and check whether it is solid. If it is, mark that direction (The direction linked to the point, that I created earlier) as solid.
- After checking all of the points, only apply the physics to X and/or Y if no collision is detected for that direction.
The issue is, that when it's finished checking for collisions, if the player is falling the collision for Left and Right will be triggered, as well as Down. This is because it doesn't order collisions; or limit it to just one collision per loop. Here is a "pseudo-code" version of the loop:
LOOP tempX = x tempY = y IF up_arrow IS pressed THEN IF NOT jumping AND grounded THEN jumping = TRUE grounded = FALSE yVelocity = -(speed / 2) * 2 // Ignore division and then multiplication by 2, as I'll be using one as a modifier END IF END IF IF left_arrow IS pressed THEN IF xVelocity < speed THEN xVelocity++ END IF END IF IF right_arrow IS pressed THEN IF xVelocity > -speed THEN xVelocity-- END IF END IF xVelocity *= friction yVelocity += gravity grounded = false // COLLISION POINT GENERATION - See below moveLeft = true moveRight = true moveDown = true moveUp = true FOREACH points AS p thisTile = findTile(p.x, p.y) // Gets the Tile instance for the given co-ords thisSolid = thisTile.isSolid() IF thisSolid THEN SWITCH p.direction CASE 0 // Left moveLeft = false BREAK CASE 1 // Right moveRight = false BREAK CASE 2 // Up moveUp = false BREAK CASE 3 // Down moveDown = false BREAK END SWITCH END IF END FOREACH IF !moveDown THEN yVelocity = 0 jumping = false grounded = true END IF IF !moveLeft OR !moveRight THEN xVelocity = 0 jumping = false END IF IF grounded THEN yVelocity = 0 END IF x += xVelocity y += yVelocity END LOOP
Collision Point Generation:
In order to check for collisions around the player, the sprite is used to calculate points in which to check for collisions. The points is generates look like this:
Each point has a Direction value so that the collision can be corrected based on that. Each point is also generated using a tempX and tempY value, which are just temporary variables which will have the players velocities applied to them before point generation, and then the point generation will use these values.
So, even if the player falls a long distance and hits the floor, because the new X and Y values it uses are un a tile, the Left and Right points are also in the floor tiles and trigger a collision.
I have no idea how to get around this; so any help is greatly appreciated!