Here is some actual working code.

Again, replace "LESS_THAN" with the less than character.

This now includes moving left and right as well.

[pascal]Const
{................................................. .............................}
cMapWidth = 20;
cMapHeight = 20;
cTileWidth = 20;
cTileHeight = 16;
{................................................. .............................}

Type
{................................................. .............................}
TTile = Record
id : Integer;
IsSolid : Boolean;
End;
{................................................. .............................}

{................................................. .............................}
TPoint = Record
x,y : Integer;
End;
{................................................. .............................}

{................................................. .............................}
TPlayer = Class
Public
x : Single;
y : Single;
vx : Single;
vy : Single;
w : Integer;
h : Integer;
CnrUL : TPoint; // upper left tile (x,y) player is over
CnrUR : TPoint; // upper right tile (x,y) player is over
CnrLL : TPoint; // lower left tile (x,y) player is over
CnrLR : TPoint; // lower right tile (x,y) player is over
Private
Procedure GetCornersAt(Const ax,ay : Single);
Public
Procedure Update(Const ATimeSlice : Single);
End;
{................................................. .............................}

Var
Tiles : Array[0..cMapHeight - 1,0..cMapWidth - 1] Of TTile;
{................................................. .............................}

{................................................. .............................}
Function Floor(X : Extended) : Integer;
Begin
Result := Integer(Trunc(X));
If Frac(X) LESS_THAN 0 Then Dec(Result);
End;
{................................................. .............................}

{................................................. .............................}
Function TileIsWalkable(Const tx,ty : Integer) : Boolean;
Begin
Result := False;
If tx LESS_THAN 0 Then Exit;
If ty LESS_THAN 0 Then Exit;
If tx >= cMapWidth Then Exit;
If ty >= cMapHeight Then Exit;
Result := Not Tiles[ty,tx].IsSolid;
End;
{................................................. .............................}

{................................................. .............................}
Function ClampValue(Const n,l,u : Integer) : Integer;
Begin
Result := n;
If Result LESS_THAN l Then Result := l
Else
If Result > u Then Result := u;
End;
{................................................. .............................}

{................................................. .............................}
Procedure TPLayer.GetCornersAt(Const ax,ay : Single);
{
|
|
-,- | +,-

-------|-------

-,+ | +,+
|
|
}
Begin
CnrUL.x := Floor((ax - w/2) / cTileWidth);
CnrUL.y := Floor((ay - h/2) / cTileHeight);

CnrUR.x := Floor((ax + w/2) / cTileWidth);
CnrUR.y := Floor((ay - h/2) / cTileHeight);

CnrLR.x := Floor((ax + w/2) / cTileWidth);
CnrLR.y := Floor((ay + h/2) / cTileHeight);

CnrLL.x := Floor((ax - w/2) / cTileWidth);
CnrLL.y := Floor((ay + h/2) / cTileHeight);

CnrUL.x := ClampValue(CnrUL.x,0,cMapWidth - 1);
CnrUR.x := ClampValue(CnrUR.x,0,cMapWidth - 1);
CnrLR.x := ClampValue(CnrLR.x,0,cMapWidth - 1);
CnrLL.x := ClampValue(CnrLL.x,0,cMapWidth - 1);

CnrUL.y := ClampValue(CnrUL.y,0,cMapHeight - 1);
CnrUR.y := ClampValue(CnrUR.y,0,cMapHeight - 1);
CnrLR.y := ClampValue(CnrLR.y,0,cMapHeight - 1);
CnrLL.y := ClampValue(CnrLL.y,0,cMapHeight - 1);
End;
{................................................. .............................}

{................................................. .............................}
Procedure TPlayer.Update(Const ATimeSlice : Single);
Var
TileIsWalkableUL : Boolean; // upper left player corner tile is walkable
TileIsWalkableUR : Boolean; // upper right player corner tile is walkable
TileIsWalkableLL : Boolean; // lower left player corner tile is walkable
TileIsWalkableLR : Boolean; // lower right player corner tile is walkable
Begin
GetCornersAt(x,y + vy * ATimeSlice);
If vy LESS_THAN 0 Then
//moving up
Begin
TileIsWalkableUL := TileIsWalkable(CnrUL.x,CnrUL.y);
TileIsWalkableUR := TileIsWalkable(CnrUR.x,CnrUR.y);
If TileIsWalkableUL And TileIsWalkableUR Then
y := y + vy * ATimeSlice
Else
// move player to touch tiles(s) above
y := CnrUL.y * cTileHeight + cTileHeight + h/2 + 0.01;
End
Else
If vy > 0 Then
//moving down
Begin
TileIsWalkableLL := TileIsWalkable(CnrLL.x,CnrLL.y);
TileIsWalkableLR := TileIsWalkable(CnrLR.x,CnrLR.y);
If TileIsWalkableLL And TileIsWalkableLR Then
y := y + vy * ATimeSlice
Else
// move player to sit on tile(s) below
y := CnrLR.y * cTileHeight - h/2 - 0.01;
End;

GetCornersAt(x + vx * ATimeSlice,y);
If vx LESS_THAN 0 Then
//moving left
Begin
TileIsWalkableUL := TileIsWalkable(CnrUL.x,CnrUL.y);
TileIsWalkableLL := TileIsWalkable(CnrLL.x,CnrLL.y);
If TileIsWalkableUL And TileIsWalkableLL Then
x := x + vx * ATimeSlice
Else
// move player to touch tiles(s) on left
x := CnrUL.x * cTileWidth + cTileWidth + w/2 + 0.01;
End
Else
If vx > 0 Then
//moving right
Begin
TileIsWalkableUR := TileIsWalkable(CnrUR.x,CnrUR.y);
TileIsWalkableLR := TileIsWalkable(CnrLR.x,CnrLR.y);
If TileIsWalkableUR And TileIsWalkableLR Then
x := x + vx * ATimeSlice
Else
// move player to touch tile(s) on right
x := CnrUR.x * cTileWidth - w/2 - 0.01;
End;
// add gravity to vy here and cap to max velocity so not faster than tile height;
End;[/pascal]

This is how I am using it:

[pascal] FPlayer := TPlayer.Create;
FPlayer.w := cTileWidth - 5;
FPlayer.h := cTileHeight - 5;
FPlayer.x := cMapWidth * cTileWidth / 2;
FPlayer.y := cMapHeight * cTileHeight / 2;
FPlayer.vx := 0;
FPlayer.vy := 0;

[/pascal]

[pascal]
FPlayer.vx := 0;
FPlayer.vy := 0;
If FMoveUp Then
FPlayer.vy := -cPlayerSpeed
Else
If FMoveDown Then
FPlayer.vy := +cPlayerSpeed;

If FMoveLeft Then
FPlayer.vx := -cPlayerSpeed
Else
If FMoveRight Then
FPlayer.vx := +cPlayerSpeed;

FPlayer.Update(TimeSlice);
[/pascal]

where TimeSlice is the time for the last frame in seconds (floating point)

Cheers,
Paul