(Characters are always 16 x 16 pixels. And the playfield data is also divided into blocks of 16 x 16 pixels.)
However, I'm asking myself whether these checks and the function in general can be optimized.
I'm not talking about compiler-related stuff like using global variables instead of local ones etc. Those are things I can easily change after finishing the function.
I'm talking about actual algorithm-related things: Can I re-structure the code to make it more simple?
The thing that bothers me the most is the loop:
Let's say a character shall move five pixels to the right. But there's a wall.
Now, it's not enough to simply check for the collision and finish the function when finding the wall. Instead, I have to check: If he cannot walk five pixels, can he walk four pixels? Three? Two? One?
Is there some way to find out how many pixels the character can walk until he hits a wall, without using a loop?
And do you see any other possible optimizations in the function?
(The current code is only for moving right and left since vertical collision detection would pretty much have equivalent code again anyway.)
Code: Select all
void CheckBackgroundCollisionAndUpdatePosition(byte pixels)
{
byte collisionX;
byte collisionTile16X;
byte collisionTile16YTop;
byte collisionTile16YBottom;
byte newCollisionX;
byte newCollisionTile16X;
byte previousCollisionTile16X;
switch (Char.HorizontalDirection)
{
case DirectionNone:
return;
case DirectionLeft:
collisionX = Char.X;
newCollisionX = collisionX - pixels;
break;
default: /* DirectionRight */
collisionX = Char.X + (16 - 1);
newCollisionX = collisionX + pixels;
break;
}
collisionTile16X = collisionX / 16;
collisionTile16YTop = Char.Y / 16;
collisionTile16YBottom = (Char.Y + (16 - 1)) / 16;
newCollisionTile16X = newCollisionX / 16;
while (true)
{
if (newCollisionTile16X == collisionTile16X
|| (GetPlayfieldValue(newCollisionTile16X, collisionTile16YTop) == TileStatusWalkable
&& GetPlayfieldValue(newCollisionTile16X, collisionTile16YBottom) == TileStatusWalkable))
{
Char.X =
Char.HorizontalDirection == DirectionLeft
? newCollisionX
/* Char.HorizontalDirection == DirectionRight */
: newCollisionX - (16 - 1);
return;
}
do
{
if (--pixels == 0)
{
Char.HorizontalDirection = DirectionNone;
return;
}
if (Char.HorizontalDirection == DirectionLeft)
++newCollisionX;
else /* Char.HorizontalDirection == DirectionRight */
--newCollisionX;
previousCollisionTile16X = newCollisionTile16X;
newCollisionTile16X = newCollisionX / 16;
}
while (newCollisionTile16X == previousCollisionTile16X);
}
}