-
Notifications
You must be signed in to change notification settings - Fork 0
Collisions
Collisions, in Mine DS, are as one would expect — box based. The collisions are calculated in mobFunctions.cpp and called within mobHandler.cpp for most mobs. The functions checks whether any of the size points in the diagram below are within a block. Next, if it finds one point is within but another is out, the mob's position is corrected such that the edge lies outside the box. Lastly, the collision booleans are filled by testing the pixels one outside the points.
So, for instance, if point 5 were inside a block and point 4 were free, the player would be shifted to the left to free point 5. However, if both points 4 and 5 are within a block, point 3 would be tested and if free, the player would move upwards to free points 4 and 5.
The graphic frame is the area the player is drawn within. The size must be larger than the collision box to accommodate animations in which the player's legs extend beyond the collision box.
bool BaseMob::isInBlock(WorldObject &world)
{
int addY = sy / (smallMob ? 1 : 2) - 1;
for (int x = this->x - sx / 2 + 1; x < this->x + sx / 2 + 1; x += sx - 1)
for (int y = this->y - sy / 2 + 1; y < this->y + sy / 2; y += addY)
if (!isBlockWalkThrough(world.blocks[x / 16][y / 16]))
return true;
return false;
}
Here, in BaseMob.cpp, this function checks all 6 points and returns false, only if every point is not inside a block.
int addY = sy / (smallMob ? 1 : 2) - 1;
Here we can see how if a mob is small (Such as a sheep or cow), the only the equivalent points 0, 1, 4, and 5 will be checked. This is because a small mob's sy is less than the minimum block size (16px) and thus, the middle two collision points would always return the same as either the top or bottom set.
for (int x = this->x - sx / 2 + 1; x < this->x + sx / 2 + 1; x += sx - 1)
The for loop begins at the left edge of the collision box, which is x - sx / 2 + 1
. The loop continues until the x value goes past the right edge of the collision box, x + sx / 2
.
if ((!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y - mob->sy / 2 + 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y - mob->sy / 2 + 1) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y + mob->sy / 2 - 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y + mob->sy / 2 - 1) / 16])))
mob->x -= int(mob->x + mob->sx / 2) % 16 + 1;
else if ((!isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y - mob->sy / 2 + 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y - mob->sy / 2 + 1) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y + mob->sy / 2 - 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y + mob->sy / 2 - 1) / 16])))
mob->x += 16 - int(mob->x - mob->sx / 2 + 1) % 16;
else if (int(mob->y) % 16 < 9)
mob->y -= int(mob->y) % 16;
This block of code, run when inside a block, moves the player to the correct location based on which points are free.
if (int(mob->y) % 16 < 3)
mob->y -= int(mob->y) % 16;
This moves the player to the top of the block if they are less than 3 pixels into the surface. This is needed
if ((!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y - mob->sy / 2 + 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y - mob->sy / 2 + 1) / 16]))
||
(!isBlockWalkThrough(world.blocks[int(mob->x + mob->sx / 2) / 16][int(mob->y + mob->sy / 2 - 1) / 16])
&& isBlockWalkThrough(world.blocks[int(mob->x - mob->sx / 2 + 1) / 16][int(mob->y + mob->sy / 2 - 1) / 16])))
mob->x -= int(mob->x + mob->sx / 2) % 16 + 1;
This part checks for a left point being free with a right one being inside a block. In this case it would move the x position to the left. The next part repeats the process except checking for a free right point with a corresponding right point inside a block.
else if (int(mob->y) % 16 < 9)
mob->y -= int(mob->y) % 16;
Here, if all else fails, it will move the player to the top of the block rather than wasting cpu time repeating the process for vertical sets of points. The maximum amount a mob can get into a block through falling is less than 9 pixels, due to the velocity cap.