I have very simple collision requirements. I need circles to collide with circles and circles to collide with 1x1 tiles. I have written up a method to try and handle the circle-tile collisions and it isn't quite working. Any help would be appreciated.
First, I scan for collisions depending on which way the entity is moving.
void PhysicsSystem::scan_collisions(DynamicEntity& entity)
{
int px, py;
px = (int)std::floor(entity.pos.x());
py = (int)std::floor(entity.pos.y());
if (entity.vel.x() > 0)
{
for (auto y = py - 1; y <= py + 1; ++y)
{
if ((px + 1) < 0 || (px + 1) >= MAP_SIZE_X || y < 0 || y >= MAP_SIZE_Y)
continue;
if (map_system.get_tile((px + 1), y, entity.floor).solid)
resolve_collision(entity, (px + 1), y);
}
}
else if (entity.vel.x() < 0)
{
for (auto y = py - 1; y <= py + 1; ++y)
{
if ((px - 1) < 0 || (px - 1) >= MAP_SIZE_X || y < 0 || y >= MAP_SIZE_Y)
continue;
if (map_system.get_tile((px - 1), y, entity.floor).solid)
resolve_collision(entity, (px - 1), y);
}
}
... [same for y-direction]
}
And here is the resolution method:
void PhysicsSystem::resolve_collision(DynamicEntity& entity, int x, int y)
{
Vector2f tile_pos(x, y);
Vector2f nearest(entity.pos);
Vector2f min(x, y), max(x + 1, y + 1);
if (nearest.x() < min.x()) nearest.x() = min.x();
else if (nearest.x() > max.x()) nearest.x() = max.x();
if (nearest.y() < min.y()) nearest.y() = min.y();
else if (nearest.y() > max.y()) nearest.y() = max.y();
Vector2f ray(entity.pos - nearest);
auto length = ray.norm();
auto depth = entity.size - length;
if (length != 0 && depth > 0)
{
ray.normalize();
entity.pos += depth * ray;
}
}
But this collides too soon when the player is walking to the left or walking up and hits a tile.