Hello!

There is such a hierarchy:

class RigidBody{ ... protected: sf::FloatRect rect; }; class Item : public RigidBody{ ... }; class Block : public Item{ ... }; 

Individually, all classes work fine. But if I convert Block *[] to RigidBody ** for processing physics inside the parent, the value of the rect variable is not saved (reset):

 Block *blocks[20]; ... RigidBody **bodys = (RigidBody **)blocks; 

How to fix this? Thank!

UPDATE: updatePhysics

 void RigidBody::updatePhysics(sf::Time dt, RigidBody **bodys, int numBodys){ float elapsed = dt.asSeconds(); if(this->dynamic){ this->velocity.x += this->acceleration.x * elapsed; // NOTE: Maybe I'll need to add gravity by x this->velocity.y += this->acceleration.y * elapsed + GRAVITY; if(abs(this->velocity.x) > this->maxVelocity.x){ this->velocity.x = ((this->velocity.x > 0) ? 1 : -1) * this->maxVelocity.x; } if(abs(this->velocity.y) > this->maxVelocity.y){ this->velocity.y = ((this->velocity.y > 0) ? 1 : -1) * this->maxVelocity.y; } this->rect.left += this->velocity.x * elapsed; this->rect.top += this->velocity.y * elapsed; } else { this->velocity.x += this->acceleration.x * elapsed; this->velocity.y += this->acceleration.y * elapsed; this->rect.left += this->velocity.x * elapsed; this->rect.top += this->velocity.y * elapsed; } for(int i = 0; i < numBodys; i++){ this->checkCollisionAndResolve(bodys[i]); } } 

UPDATE 2: checkCollisionAndResolve

 bool RigidBody::checkCollisionAndResolve(RigidBody *object){ // TODO: add other collision types support bool isColliding = this->rect.intersects(object->rect); if(object->bodyType != RIGIDBODY_NONE && isColliding){ sf::Vector2f centers[2]; centers[0] = object->getCenter(); centers[1] = this->getCenter(); int distanceByX = (centers[0].x - centers[1].x) / (object->getWidth() / 2); int distanceByY = (centers[0].y - centers[1].y) / (object->getHeight() / 2); int absoluteDistanceByX = abs(distanceByX); int absoluteDistanceByY = abs(distanceByY); if(abs(absoluteDistanceByX - absoluteDistanceByY) < 0.1f){ // Corner collision if(distanceByX < 0){ this->rect.left = object->getRight(); if(this->velocity.x < 0){ this->velocity.x = 0; } } else { this->rect.left = object->getLeft() - this->getWidth(); if(this->velocity.x > 0){ this->velocity.x = 0; } } if(distanceByY < 0){ this->rect.top = object->getBottom(); if(this->velocity.y < 0){ this->velocity.y = 0; } } else { this->rect.top = object->getTop() - this->getHeight(); if(this->velocity.y > 0){ this->velocity.y = 0; } } if(rand() % 2){ this->velocity.x = -this->velocity.x * object->getRestitution(); } else { this->velocity.y = -this->velocity.y * object->getRestitution(); } } else if(absoluteDistanceByX > absoluteDistanceByY){ // Side collision if(distanceByX < 0){ this->rect.left = object->getRight(); this->velocity.x = 0; } else { this->rect.left = object->getLeft() - this->getWidth(); this->velocity.x = 0; } this->velocity.x = -this->velocity.x * object->getRestitution(); } else { // Bottom or top collision if(distanceByY < 0){ this->rect.top = object->getBottom(); this->velocity.y = 0; } else { this->rect.top = object->getTop() - this->getHeight(); this->velocity.y = 0; } //this->velocity.y = -this->velocity.y * object->getRestitution(); } } return isColliding; } 
  • pastebin.com/NdC0DHaG - headers ... pastebin.com/4MB7wkLU - call - user26699
  • Yes. But the type is changing. And because of this, the values ​​of the variables are reset. - user26699
  • Specifically, rect is nullified when casting to RigidBody ** . - user26699
  • Perhaps you have not read: the minimum reproducible example - VladD
  • You have sf::FloatRect rect; - protected , and in pastebin - public . Is this a typo or is the code wrong? Show the value of rect before and after the line RigidBody **bodys = (RigidBody **)blocks; - add code with rect output in the question around this line. - Igor

1 answer 1

You get undefined behavior, in other words, your code is incorrect. Let's figure it out: you have an array of pointers to the Block that you force to double the pointer to a RigidBody . Try to bring it with static_cast - it will not work and it should alert you already.

So, we have led to RigidBody** and now we are moving through the array: everything is fine, because an array of pointers, then there is no problem - no matter what the pointer is, its size is always the same (almost, but it doesn’t matter here). The problem begins further, you are running this line:

 this->checkCollisionAndResolve(bodys[i]); 

What is bodys[i] ? This is a pointer to a Block . Does the function know about this? No, of course, for her this is a pointer to RigidBody ! And everything would be fine, and it would even work, but here only with the Item pointer to the table of virtual functions came to our object and broke everything. You can't just interpret the pointer to Block as a pointer to RigidBody , you need to convert. And the function does not know anything about it, so you have what you have.

Morale one: never convert arrays of types, to other types it never ends in anything good.

Morale two: never use the C-style conversion, it only hides mistakes from you.

  • How then can I do a physics check? Write separate methods for the Item , Block classes and other descendants? - user26699
  • @reload, you have to think about how to organize it. It's hard for me to say something without seeing the whole code. It is always possible to unify without skipping to repeat the code. You just need to think of how. - ixSci
  • > Moral two: never use the C-style conversion, it only hides mistakes from you. That is only through static_cast <> ? - user26699
  • one
    @reload, it is possible through other C ++ conversion operators, so that it is obvious what is happening. static_cast is the safest. - ixSci