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 Answer 1

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .