Here is what I usually use.
I have not checked it, but I hope it does not contain any mistakes.
Yes, it's a bit complex, but it gives very nice platformer physics.
int x = /*...*/, y = /*...*/; // Player coords.
int xv = 0, yv = 0; // Player horisontal and vertical speed.
/// Returns true if left key is being held.
bool LeftKeyHold() {/*...*/}
/// Returns true if right key is being held.
bool RightKeyHold() {/*...*/}
/// Returns true if jump key is was pressed at previous tick.
bool JumpKeyPressed() {/*...*/}
/// This func tests if point at specific coords can be passed through.
bool IsSolidAt(int xpos, int ypos) {/*...*/}
// Just divide xpos and ypos by tile size and check if tile at this position
// is solid. If so, return true, else false. Don't forget to check if these
// coordinates are in correct range, and if they are not, return false.
// (Or true if you want solid map border.)
/// This func tests if player would be inside a wall at specific location
bool IsPosSolidForPlayer(int xpos, int ypos)
{
return IsSolidAt(xpos - 5, ypos - 5) ||
IsSolidAt(xpos + 5, ypos - 5) ||
IsSolidAt(xpos + 5, ypos + 5) ||
IsSolidAt(xpos - 5, ypos + 5);
// These are "collision points" of a character. They are relative to
// player's center.
// Usually they are just corner points of a character. In this case
// character is 11x11 pixels.
// If character is larger than tile, you MUST add more points, look at
// image below.
// Distance between two nearest points MUST be smaller than tile size.
// If it is larger, add more points. Toooo many points is bad because
// it can become slow.
// Character exapmples
// |
// +--------+-----+
// | |
// V | 'o's are collision points.
// |
// o'''o'''o V
// : :
// o x o o'''o #####
// : : : x : ##### <-- Tile
// o...o...o o...o #####
//
// ^ ^
// | |
// | +-- No extra points needed if character is small.
// +-- Notice the extra points at sides' centers. You would need
// more if character is bigger.
}
/* ... */
while (true) // Main loop.
{
/*...*/
yv += 1;
// Use another number if you want different gravity acceleration.
// Remove completely if you don't need gravity.
// Also modify xv if you want horisontal gravity too.
// I assume you have fixed FPS. If not, you must add 'tick delta'
// multiplied by some number instead of fixed number.
// Code below controls horisontal movement, remove if not needed.
const int movementvel = 5; // Maximum movement velocity, pixels per tick.
int hc = (RightKeyHold() - LeftKeyHold()) * 1; // Replace 1 with desired
// player acceleration or leave it as 1 if you don't care.
if (!hc)
{
// Speed at which player loses it's velocity if he is not
// controlled. You can replace 1 with any number or leave it as 1
// if you don't care.
xv -= ((xv > 0) - (xv < 0)) * 1;
}
else
{
xv += hc;
if (xv > movementvel) xv = movementvel;
else if (xv < -movementvel) xv = -movementvel;
}
// Code below controls jumps, remove if not needed.
if (JumpKeyPressed() && IsPosSolidForPlayer(x, y+1))
yv = -10; // Replace -10 with desired jump power. It should be negative.
// Code below moves player depending on his velocity. Collision is
// pixel-perfect, character can't stuck inside a wall with it.
const int maxvel = 10; // Maximum velocity, pixels per tick.
if (xv)
{
int v = xv;
if (v > 0)
{
if (v > maxvel) v = maxvel;
while (v--)
{
if (!IsPosSolidForPlayer(x+1, y))
x += 1;
else
{
xv = 0;
break;
}
}
if (v && IsPosSolidForPlayer(x+1, y)) xv = 0;
}
else
{
if (v < -maxvel) v = -maxvel;
while (v++)
{
if (!IsPosSolidForPlayer(x-1, y))
x -= 1;
else
{
xv = 0;
break;
}
}
if (v && IsPosSolidForPlayer(x-1, y)) xv = 0;
}
}
if (yv)
{
int v = yv;
if (v > 0)
{
if (v > maxvel) v = maxvel;
while (v--)
{
if (!IsPosSolidForPlayer(x, y+1))
y += 1;
else
{
yv = 0;
break;
}
}
if (v && IsPosSolidForPlayer(x, y+1)) yv = 0;
}
else
{
if (v < -maxvel) v = -maxvel;
while (v++)
{
if (!IsPosSolidForPlayer(x, y-1))
y -= 1;
else
{
yv = 0;
break;
}
}
if (v && IsPosSolidForPlayer(x, y-1)) yv = 0;
}
}
/*...*/
}