I am a beginner trying to implement some AABB collision detection. I'm following along with the excellent COMP4300 Game Programming lecture series on Youtube by Professor Dave Churchill but I'm now stuck.
After watching his lecture on collision detection and resolution I believe I have implemented everything as instructed. The collision detection works fine but the resolution of detecting how much overlap there is and pushing back the sprite by the amount of overlap is not working as expected.
As you can see in the linked video, the resolution only works against the tiles at the very top of the screen. Note that I'm only testing for horizontal collision.
According to the lecture I had to create two helper functions: getOverlap and getPreviousOverlap, which is just a copy and paste of getOverlap but uses the entity's previous frame's position.
If getOverlap x and y are both greater than 0 then there's a collision. This part works.
To see if it was horizontal collision I use the formula if(prevOverlap.y > 0) {}
However; apart from the tiles at the top, this condition is not being met.
Link to demo video
https://streamable.com/mj9o61// Collision system in Scene_Play.cpp
void Scene_Play::sCollision()
{
auto& playerTransform = m_player->getComponent<CTransform>();
auto& playerBoundingBox = m_player->getComponent<CBoundingBox>();
auto& playerState = m_player->getComponent<CState>().state;
for (auto& e : m_entityManager.getEntities("tile"))
{
Vec2 overlap = Physics::getOverlap(m_player, e);
Vec2 prevOverlap = Physics::getPreviousOverlap(m_player, e);
auto& entityTransform = e->getComponent<CTransform>();
if(overlap.x > 0 && overlap.y > 0)
{
std::cout << "Collision detected" << std::endl;
if (prevOverlap.y > 0) {
std::cout << "Horizontal collision" << std::endl;
// Calcualte if from left or right collision occurred
playerTransform.pos.x = (playerTransform.pos.x < entityTransform.pos.x) ? playerTransform.pos.x -= overlap.x : playerTransform.pos.x += overlap.x;
}
}
}
}
//Helper functions in Physics.cpp
Vec2 Physics::getOverlap(std::shared_ptr<Entity> player, std::shared_ptr<Entity> entity)
{
auto& playerTransform = player->getComponent<CTransform>();
auto& playerBoundingBox = player->getComponent<CBoundingBox>();
auto& entityTransform = entity->getComponent<CTransform>();
auto& entityBoundingBox = entity->getComponent<CBoundingBox>();
Vec2 delta = { abs(entityTransform.pos.x - playerTransform.pos.x), abs(entityTransform.pos.y - playerTransform.pos.y) };
float ox = (entityBoundingBox.halfSize.x + playerBoundingBox.halfSize.x) - delta.x;
float oy = (entityBoundingBox.halfSize.y + playerBoundingBox.halfSize.y) - delta.y;
if (ox > 0 && oy > 0) return Vec2(ox, oy);
return Vec2(0.0f, 0.0f);
}
Vec2 Physics::getPreviousOverlap(std::shared_ptr<Entity> player, std::shared_ptr<Entity> entity)
{
auto& playerTransform = player->getComponent<CTransform>();
auto& playerBoundingBox = player->getComponent<CBoundingBox>();
auto& entityTransform = entity->getComponent<CTransform>();
auto& entityBoundingBox = entity->getComponent<CBoundingBox>();
Vec2 delta = { abs(entityTransform.prevPos.x - playerTransform.prevPos.x), abs(entityTransform.prevPos.y - playerTransform.prevPos.y) };
float ox = (entityBoundingBox.halfSize.x + playerBoundingBox.halfSize.x) - delta.x;
float oy = (entityBoundingBox.halfSize.y + playerBoundingBox.halfSize.y) - delta.y;
if (ox > 0 && oy > 0) return Vec2(ox, oy);
return Vec2(0.0f, 0.0f);
}