#weirdness going on inside Collision Detection System
125 messages · Page 1 of 1 (latest)
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.
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
what kind of collision is this? and i see rigid body, is this inside of a game engine?
the code is very complex and i dont have the time to fully look through it right now
honestly i dont know what type of collision this is, i like to implement things without knowing how to implement them
yes, this is a self made gameengine
so you didnt make this collision system, did you follow a tutorial or use chatgpt?
i did, but i didnt follow a "blueprint"
but if i were to guess id say its like an axis overlap checking collisions
nice
oh like sat
your method seems very complex
im not really able to follow it
so what is not working about it?
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)
oh so objects can push eachother?
yea
so do you actually have rigidbody
are you using box2d or did you implement it yourself
the weirdest part is that it somewhat works when i use std::cout << xChain() << "\n" which i know should affect anything
i implemented it myself
thats really cool
thats weird
are you using multithreading?
nope
i am using std::vectors tho, thats like the only thing i didnt make myself (yet)
what doesnt work about it when you exclude the cout
im currently writing my own game engine/collision system right now as well so i understand your pain
without std::cout
with cout::
its so weird i dont know how it is even affecting the physics
opengl
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
works or doesnt work?
doesnt; i still phase into objects when i comment out std::cout
can you show the portion of the code with the cout
for (auto col : GameObject::colliders) {
std::cout << xChain(velocity.x) << "\n";
}```
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
well when you comment the cout your commenting that function
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;
}```
did
it still makes the player phase into objects (altough its less common than if i dont include the cout line)
the point was to put another kind of dely right where the std::cout is
thats very strange
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
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
tried that, didnt change anything...
yeah, it still works
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)
yeah im doing everything on a single thread, i do use thread.sleep() but it shouldnt affect it to my knowledge..
why are you using thread sleep?
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
// 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;
what is weird about it?
what is xChain supposed to return
the direction of the push?
its supposed to return -1 if the push chain is in any way obstructed ie has a static object in its path
so the 0's are abnormal?
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
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
im just passing vel back into itself as of rn,
so it recursively modifies vel?
would you want to pass a reference
int xChain(float& vel) {
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;
};
}```
ok before we do anything, your code works when you use the cout right?
collision in general works; but the output of the cout is completely wrong
It returns 0 even if i can clearly see that the path is obstructed,
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
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
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'.
hmm, that would kinda explain the bounce back
If your frametime can be negative, that would explain that push's sigidness was changed and it pulled the object instead of pushing it.
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