1
\$\begingroup\$

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:

enter image description here

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.

\$\endgroup\$
1
\$\begingroup\$

Okay, I figured out what was wrong!

I needed to change

if(overlapping.x < overlapping.z){
  position->x += overlapping.x;
}else{
  position->z += overlapping.z;
}

to

if(std::abs(overlapping.x) < std::abs(overlapping.z)){
  position->x += overlapping.x;
}else{
  position->z += overlapping.z;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.