#weirdness going on inside Collision Detection System

125 messages · Page 1 of 1 (latest)

simple flicker
#

For some reason my Memory detection system doesnt work properly, i keep phasing into object when they arent allowed to move. Thats all understandable, but the weird part? My code only works when i std::cout the output of a function??!?

Here is my code (or atleast the key parts)

charred briarBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

simple flicker
#
    void whereColliding(GameObject* other) {
        float thres = 0.03f;
        Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
        Vector2 scale = Vector2(parent->Scale.x, parent->Scale.y);
        if ((pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y + scale.y / 2) >= (other->position.y - other->Scale.y / 2)) {
            if (thres + (pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) - thres >= (other->position.x - other->Scale.x / 2)) {


                auto rb = other->GetComponent<Rigidbody2D>();
                if (rb && engineMath::sign(rb->parent->position.y - this->parent->position.y) == engineMath::sign(velocity.y)) {
                    float totalVel = this->velocity.y + rb->velocity.y;
                    float TotalMass = this->mass + rb->mass;
                    for (auto col : GameObject::colliders) {

                        std::cout << yChain(velocity.x) << "\n";
                    }

                    if (yChain(engineMath::sign(velocity.y)) == -1) {
                        std::cout << "HIT SOMETHING THAT CANT BE MOVED\n";
                        velocity.y = 0;
                        rb->velocity.y = 0;

                        std::cout << "NO FALL\n";
                    }
                    else {
                        float velocityPerMass = totalVel / TotalMass;
                        this->velocity.y = this->velocity.y;

                        rb->velocity.y = this->velocity.y;
                    }
                }
                else {
                velocity.y = 0;
                }
            }
        }```
#
    if ((pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) >= (other->position.x - other->Scale.x / 2)) {
        if (thres + (pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y + scale.y / 2) - thres >= (other->position.y - other->Scale.y / 2)) {

            //Transfer a part of the momentum if the other object is moveable
            auto rb = other->GetComponent<Rigidbody2D>();
            if (rb && engineMath::sign(rb->parent->position.x - this->parent->position.x) == engineMath::sign(velocity.x)) {
                float totalVel = this->velocity.x + rb->velocity.x;
                float TotalMass = this->mass + rb->mass;

                for (auto col : GameObject::colliders) {

                    std::cout << xChain(velocity.x) << "\n";
                }
                if (xChain(velocity.x) == -1) {
                    this->velocity.x = 0;
                    rb->velocity.x = 0;
                    std::cout << "IMMOVEABLE\n";
                    return;
                }
                else {
                    float velocityPerMass = totalVel / TotalMass;
                    this->velocity.x = this->velocity.x;

                    rb->velocity.x = this->velocity.x;
                }
            }

            else{

                //Touching a Static Object
                velocity.x = 0;
            }

            //std::cout << "Size of x chain = " << Chain.size() << " \n";
        }
    }

}```
#
public:


    int xChain(float vel) {
        Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
        Vector2 scale = Vector2(parent->Scale.x, parent->Scale.y);
        float thres = 0.2f;
        for (GameObject* other : GameObject::colliders) {

            if (other == this->parent) continue;
            if (engineMath::sign(other->position.x - this->parent->position.x) != engineMath::sign(vel)) continue;
            if (!((pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) >= (other->position.x - other->Scale.x / 2))) continue;
            if (!( (thres + pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y - thres + scale.y / 2)  >= (other->position.y - other->Scale.y / 2))) continue;
            auto rb = other->GetComponent<Rigidbody2D>();
            if (!rb) {
                this->velocity.x = 0;

                return -1;
            }

            if (!(std::find(rb->touchChain.begin(), rb->touchChain.end(), this->parent) == rb->touchChain.end())) continue;
            touchChain.push_back(rb->parent);

            if (rb->xChain(vel) == -1) {
                this->velocity.x = 0;
                return -1;
            };

        }
        this->velocity.x = vel;
        touchChain.clear();
        return 0;

    }```
#
int yChain(float vel) {
    Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
    Vector2 scale = Vector2(parent->Scale.x, parent->Scale.y);
    float thres = 0.2f;
    for (GameObject* other : GameObject::colliders) {
        if (other == this->parent) continue;
        if (engineMath::sign(other->position.y - this->parent->position.y) != engineMath::sign(vel)) continue;
        if (!((pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y + scale.y / 2) >= (other->position.y - other->Scale.y / 2))) continue;
        if (!((thres + pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x - thres + scale.x / 2)  >= (other->position.x - other->Scale.x / 2))) continue;
        auto rb = other->GetComponent<Rigidbody2D>();
        if (!rb) {
            this->velocity.y = 0;
            return -1;
        }
        if (!(std::find(rb->touchChain.begin(), rb->touchChain.end(), this->parent) == rb->touchChain.end())) continue;
        touchChain.push_back(rb->parent);
        if (rb->yChain(vel) == -1) {
            this->velocity.y = 0;
            return -1;
        }
    }
    this->velocity.y = vel;
    touchChain.clear();
    return 0;

}```
#

please dont mind the ugly formatting and the redundant code, I have been dissecting it for the past few hours to get to the bottom of the phasing problem

#

    void Update() override {
        //gravity 
        velocity.y -= gravity * Time::deltaTime;
        //collision
        checkCollision();

        //Movement
        this->parent->position.x += velocity.x * Time::deltaTime;
        this->parent->position.y += velocity.y * Time::deltaTime;


        //Friction
        velocity.x *= engineMath::clamp(1 - Friction * Time::deltaTime);
        velocity.y *= engineMath::clamp(1 - Friction * Time::deltaTime);
        if (engineMath::absolute(velocity.x) < threshhold * Time::deltaTime) velocity.x = 0;
        if (engineMath::absolute(velocity.y) < threshhold * Time::deltaTime) velocity.y = 0;


    }
#
void checkCollision() {
    for (auto col : GameObject::colliders) {
        if (col == parent) continue;
        isColliding(col);
    }
}

bool isColliding(GameObject* other) {


    float thres = 0.2f;
    Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
    Vector2 scale = Vector2(parent->Scale.x + thres, parent->Scale.y + thres);

    if ((pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) >= (other->position.x - other->Scale.x / 2)) {
        if ((pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y + scale.y / 2) >= (other->position.y - other->Scale.y / 2)) {

            whereColliding(other);
            return true;
        }
    }
    return false;

}```
#

i just keep on phasing into objects.

#

feel free to ping me

bitter elm
#

the code is very complex and i dont have the time to fully look through it right now

simple flicker
simple flicker
bitter elm
#

so you didnt make this collision system, did you follow a tutorial or use chatgpt?

simple flicker
bitter elm
#

oh i see yeah

#

thats what i do as well

simple flicker
#

but if i were to guess id say its like an axis overlap checking collisions

simple flicker
bitter elm
#

oh like sat

#

your method seems very complex

#

im not really able to follow it

#

so what is not working about it?

simple flicker
#

when im pushing an object, and that object happens to collide with a wall, my player object phases into the object

#

i use a recursive chain function to check if the objects that im pushing are in a pushable state (dont collide with an object without a rigidbody in the direction of the movement)

bitter elm
#

oh so objects can push eachother?

simple flicker
#

yea

bitter elm
#

so do you actually have rigidbody

#

are you using box2d or did you implement it yourself

simple flicker
#

the weirdest part is that it somewhat works when i use std::cout << xChain() << "\n" which i know should affect anything

simple flicker
bitter elm
#

thats really cool

bitter elm
#

are you using multithreading?

simple flicker
#

nope

#

i am using std::vectors tho, thats like the only thing i didnt make myself (yet)

bitter elm
#

im currently writing my own game engine/collision system right now as well so i understand your pain

simple flicker
#

its so weird i dont know how it is even affecting the physics

bitter elm
#

thats weird

#

what are you using for rendering?

simple flicker
#

opengl

bitter elm
#

what if you replace the cout with a fake delay using chrono

#

like a 10ms delay

simple flicker
#

i have already limited the framerate using a timer function i made

#

but wait, let me slow it down a lil more

#

still the same outcome

bitter elm
#

works or doesnt work?

simple flicker
bitter elm
#

can you show the portion of the code with the cout

simple flicker
#
for (auto col : GameObject::colliders) {
    std::cout << xChain(velocity.x) << "\n";
}```
bitter elm
#

what is xChain

#

its a function?

simple flicker
# bitter elm what is xChain

its the recursive function that checks for objects colliding on the x axis, i use it to check if an object which im pushing is at any point touching a static object

bitter elm
#

well when you comment the cout your commenting that function

simple flicker
#
int xChain(float vel) {
        Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
        Vector2 scale = Vector2(parent->Scale.x, parent->Scale.y);
        float thres = 0.2f;
        for (GameObject* other : GameObject::colliders) {

            if (other == this->parent) continue;
            if (engineMath::sign(other->position.x - this->parent->position.x) != engineMath::sign(vel)) continue;
            if (!((pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) >= (other->position.x - other->Scale.x / 2))) continue;
            if (!( (thres + pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y - thres + scale.y / 2)  >= (other->position.y - other->Scale.y / 2))) continue;
            auto rb = other->GetComponent<Rigidbody2D>();
            if (!rb) {
                this->velocity.x = 0;

                return -1;
            }

            if (!(std::find(rb->touchChain.begin(), rb->touchChain.end(), this->parent) == rb->touchChain.end())) continue;
            touchChain.push_back(rb->parent);

            if (rb->xChain(vel) == -1) {
                this->velocity.x = 0;
                return -1;
            };

        }
        this->velocity.x = vel;
        touchChain.clear();
        return 0;

    }```
bitter elm
#
for (auto col : GameObject::colliders) {
    xChain(velocity.x);
}
#

just try that

simple flicker
#

it still makes the player phase into objects (altough its less common than if i dont include the cout line)

blissful ermine
bitter elm
#

to my knowledge, cout shouldnt change anything

#

especially if your program is single threaded

#

if you do std::endl instead of "\n" does it make a difference?

#

^ this is stupid but just try to for the hell of it

simple flicker
#

sure

#

doesnt really change anything...

bitter elm
#

ok good honestly

#

if you do this does it still work?

for (auto col : GameObject::colliders) {
    auto test = xChain(velocity.x);
    std::cout << test << "\n";
}
#

just trying to widdle down the weird stuff that could heppen

simple flicker
bitter elm
#

i think there is something strange happening somewhere else because this doesnt make much sense, are you sure your program isnt doing any multithreading? like inputs being on a different thread or if opengl delegates inputs to a different thread (i dont use opengl so im not sure how it works)

simple flicker
bitter elm
#

why are you using thread sleep?

simple flicker
#

to limit my frame rate, opengl should have a vsync option but it didnt work for soem strange reason

#

so i decided to do it the old fashioned way

bitter elm
#

i wouldnt recommend using that

#

ill show u how i do it

#

1 sec

simple flicker
#

sure

#

i feel like the output of the std::cout is also really weird

bitter elm
# bitter elm ill show u how i do it
        // packet limiter, only allows packets to send at 'packetSendRate'
        if (packetSendCounter > windowInfo.FRAMERATE / packetSendRate)
        {
            packetCanSend = true;
            packetSendCounter = 0;
        }

        // packet senders in this conditional will be sent at a constant rate: 'packetSendRate'
        if (packetCanSend)
        {
                client_player_action_handleMove();
        }

        // ... code ...

        ++packetSendCounter;
        packetCanSend = false;
#

i have a global var in my object for keeping track of packetSendCounter

#

this may not be the best way, but it works quite well

#

im using this to limit how many packets the client can send to the server per second

#

packetSendRate is the max per second, so your fps really

#

i have it set to 60.0f;

bitter elm
#

what is xChain supposed to return

#

the direction of the push?

simple flicker
#

its supposed to return -1 if the push chain is in any way obstructed ie has a static object in its path

bitter elm
#

so the 0's are abnormal?

simple flicker
#

yeah, im pushing the gray box into the white wall, which should obstruct the push path which in turn should return -1, but i get a mix of -1 and 0

bitter elm
#

if (rb->xChain(vel) == -1) {

do you want to pass vel back into itself, or the newly updated vel?

#

or wait

#

im not fully understanding this function so im probably asking something stupid

simple flicker
#

im just passing vel back into itself as of rn,

bitter elm
#

so it recursively modifies vel?

#

would you want to pass a reference

int xChain(float& vel) {

simple flicker
#

no, it recursivley checks if the would be position is obscured or not, which is where vel comes in. Vel is the velocity that tells me where the would be position would be

#

so essentially the function works like this

Define Would be Position
Define Scale
Loop over all Collidable Objects in Scene:
  If the current Object is the currently looped object, skip
  If the object is not in the direction of my movement, skip
  If the objects dont touch on the x axis, skip
  if the object dont touch on the y axis (with a threshhold) skip
  Check if there is a RigidBody rb
  if not, return -1 because i have hit a object that is in my path that cant be moved
  else
  check if the rigidbody rb can move in the direction of velocity vel, if it cant (returns -1) then return -1

#

thats the general way my xChain is working right now

#

(i do have a vector set up to stop the method from becoming an infinite loop)

#
int xChain(float vel) {

//Would be Positions, Scale and Threshhold
    Vector2 pos = Vector2(parent->position.x + velocity.x * Time::deltaTime, parent->position.y + velocity.y * Time::deltaTime);
    Vector2 scale = Vector2(parent->Scale.x, parent->Scale.y);
    float thres = 0.2f;

//Looping through all collidables
    for (GameObject* other : GameObject::colliders) {
//Checking wether the collidable is current objetct
        if (other == this->parent) continue;
//Checking whether its in the direction of my movement
        if (engineMath::sign(other->position.x - this->parent->position.x) != engineMath::sign(vel)) continue;

//Checking if there is any overlap
        if (!((pos.x - scale.x / 2) <= (other->position.x + other->Scale.x / 2) && (pos.x + scale.x / 2) >= (other->position.x - other->Scale.x / 2))) continue;
        if (!( (thres + pos.y - scale.y / 2) <= (other->position.y + other->Scale.y / 2) && (pos.y - thres + scale.y / 2)  >= (other->position.y - other->Scale.y / 2))) continue;
//Checking if the object is Static, ie if it has a rigidbody or not
        auto rb = other->GetComponent<Rigidbody2D>();

//If it doesnt
        if (!rb) {
            this->velocity.x = 0;

            return -1;
        }

//Stopping an infinite recursive loop
        if (!(std::find(rb->touchChain.begin(), rb->touchChain.end(), this->parent) == rb->touchChain.end())) continue;
        touchChain.push_back(rb->parent);


//check if the next object is obstructed
        if (rb->xChain(vel) == -1) {
            this->velocity.x = 0;
            return -1;
        };

    }```
bitter elm
#

ok before we do anything, your code works when you use the cout right?

simple flicker
bitter elm
#

ok maybe get that to work first, because you made the collision, you will be the best to fix it

#

then we can worry about why it only works with the cout

simple flicker
#

yeah its still not working lol

#

another weird thing is that i havent even added repel yet (y`know when you hit a wall you bounce back) but its somehow there

junior moss
#

If it works because of cout then it's likely because of a delay it creates.
That would mean that your collision system is numerically unstable.
The most common mistake I've seen is to mess up frame time calculation, where negative frametimes are 'allowed'.

simple flicker
#

hmm, that would kinda explain the bounce back

junior moss
#

If your frametime can be negative, that would explain that push's sigidness was changed and it pulled the object instead of pushing it.

simple flicker
#

ok this cant be it;
I checked for a negative time.deltaTime on each frame
i phased into the object, but there was no sign of a negative time::deltaTime

#

ok after thorough experiments i can safely say that thats not it

#

        if (engineMath::sign(Time::deltaTime) != 1) std::cout << "HERE IS WHERE THE PROBLEM LIES\n";```
#

yeah ill probably just go back to working on the engine tomorrow