I'm currently breaking my head with collision detection and resolving in C++ for my 3D game engine. But currently I'm trying to get resolving to work in 2D. The problem is that when I hit the solid object with my moving object on a specific side, it teleports the player to the edge. It's a bit hard to explain, so I gave my artistic skills a run:
Here you see, if my moving object travels from the bottom up and hits on the right side, everything works. But even if there is a little bit of an overhang on the left side, it teleports the player completely to the edge. And it does that on every side of the AABB.
I also made a short video visualizing the problem.
This is my function to return the overlapping values:
glm::vec3 Collider::getOverlapping(AABB &other, AABB &aabb) {
glm::vec3 overlappingAxis;
if( (std::abs(aabb.first()->x - other.first()->x) * 2 > (aabb.size()->x + other.size()->x)) ||
(std::abs(aabb.first()->y - other.first()->y) * 2 > (aabb.size()->y + other.size()->y)) ||
(std::abs(aabb.first()->z - other.first()->z) * 2 > (aabb.size()->z + other.size()->z))){
return overlappingAxis; //No collision occured
}
overlappingAxis.x = sign(aabb.center()->x - other.center()->x) * ((other.size()->x/2 + aabb.size()->x/2) - std::abs(aabb.center()->x - other.center()->x));
overlappingAxis.y = sign(aabb.center()->y - other.center()->y) * ((other.size()->y/2 + aabb.size()->y/2) - std::abs(aabb.center()->y - other.center()->y));
overlappingAxis.z = sign(aabb.center()->z - other.center()->z) * ((other.size()->z/2 + aabb.size()->z/2) - std::abs(aabb.center()->z - other.center()->z));
for(int i = 0; i < 3; i++){ //Add a bit of an offset so that it actually moves out of the collision
overlappingAxis[i] += sign(overlappingAxis[i]) * 0.0005;
}
return overlappingAxis;
}
My method(s) to figure return if there is actually an collision:
bool Collider::isColliding(AABB& other, glm::vec3& axis, AABB& aabb) {
axis = getOverlapping(other, aabb);
return !(axis == glm::vec3(0, 0, 0));
}
bool Collider::isColliding(AABB &other, glm::vec3 &axis) {
return isColliding(other, axis, *m_aabb);
}
My collision resolving method:
void Collider::resolveCollisions(AABB& other, glm::vec3 *position) {
glm::vec3 overlapping;
if(isColliding(other, overlapping)) {
Logger::info(glm::to_string(overlapping), 2);
if(overlapping.x < overlapping.z){
position->x += overlapping.x;
}else{
position->z += overlapping.z;
}
}
}
And my move method of the Physics Object:
void PhysicsObject::updatePosition() {
AABB testAABB(glm::vec3(0.0f, 0.0f, 0.0f) + glm::vec3(3.0f, 0.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f) + glm::vec3(3.0f, 0.0f, 1.0f));
m_transformation.getPosition().setPosition(*m_transformation.getPosition().getPosition() + velocity * glm::vec3(DeltaTime::getBigDeltaTime()));
updateAABB();
collider->resolveCollisions(testAABB, m_transformation.getPosition().getPosition());
updateAABB();
collider->resolveCollisions(testAABB, m_transformation.getPosition().getPosition());
}
Just to be clear: Because it's actually a 3D Engine, the Z-Axis represents the Y-Axis, if that makes sense! I just want to get 2D to work and then I extend to 3D!
I'm pretty sure I'm wrong in my resolveCollisions() method. I tried many things, but I just cannot figure out whats wrong.