issue #2771: fix body and joint memory bugs. add removeFormWorld and destroy to PhysicsJoint, and add a destroy param to PhysicsWorld->removeJoint()

This commit is contained in:
boyu0 2013-11-07 14:17:57 +08:00
parent 6c27a0df0b
commit f2cd5ca630
7 changed files with 176 additions and 63 deletions

View File

@ -86,22 +86,15 @@ PhysicsBody::PhysicsBody()
PhysicsBody::~PhysicsBody()
{
if (_world)
{
removeFromWorld();
}
removeAllShapes();
for (auto it = _joints.begin(); it != _joints.end(); ++it)
{
PhysicsJoint* joint = *it;
PhysicsBody* other = joint->getBodyA() == this ? joint->getBodyB() : joint->getBodyA();
other->_joints.erase(std::find(other->_joints.begin(), other->_joints.end(), joint));
other->removeJoint(joint);
delete joint;
}
CC_SAFE_DELETE(_info);
}
@ -282,6 +275,16 @@ bool PhysicsBody::init()
return false;
}
void PhysicsBody::removeJoint(PhysicsJoint* joint)
{
auto it = std::find(_joints.begin(), _joints.end(), joint);
if (it != _joints.end())
{
_joints.erase(it);
}
}
void PhysicsBody::setDynamic(bool dynamic)
{
if (dynamic != _dynamic)
@ -616,7 +619,7 @@ void PhysicsBody::removeShape(int tag)
void PhysicsBody::removeShape(PhysicsShape* shape)
{
if (_shapes->getIndexOfObject(shape) == UINT_MAX)
if (_shapes->getIndexOfObject(shape) != UINT_MAX)
{
// deduce the area, mass and moment
// area must update before mass, because the density changes depend on it.
@ -629,6 +632,9 @@ void PhysicsBody::removeShape(PhysicsShape* shape)
{
_world->removeShape(shape);
}
// set shape->_body = nullptr make the shape->setBody will not trigger the _body->removeShape function call.
shape->_body = nullptr;
shape->setBody(nullptr);
_shapes->removeObject(shape);
}
@ -650,6 +656,9 @@ void PhysicsBody::removeAllShapes()
{
_world->removeShape(shape);
}
// set shape->_body = nullptr make the shape->setBody will not trigger the _body->removeShape function call.
shape->_body = nullptr;
shape->setBody(nullptr);
}
@ -674,10 +683,10 @@ void PhysicsBody::setEnable(bool enable)
{
if (enable)
{
_world->addBody(this);
_world->delayTestAddBody(this);
}else
{
_world->removeBody(this);
_world->delayTestRemoveBody(this);
}
}
}

View File

@ -263,6 +263,8 @@ protected:
virtual void update(float delta) override;
void removeJoint(PhysicsJoint* joint);
protected:
PhysicsBody();
virtual ~PhysicsBody();

View File

@ -32,6 +32,7 @@
#endif
#include "CCPhysicsBody.h"
#include "CCPhysicsWorld.h"
#include "chipmunk/CCPhysicsJointInfo_chipmunk.h"
#include "box2d/CCPhysicsJointInfo_box2d.h"
@ -48,9 +49,11 @@ NS_CC_BEGIN
PhysicsJoint::PhysicsJoint()
: _bodyA(nullptr)
, _bodyB(nullptr)
, _world(nullptr)
, _info(nullptr)
, _enable(false)
, _collisionEnable(true)
, _destoryMark(false)
, _tag(0)
{
@ -94,12 +97,15 @@ void PhysicsJoint::setEnable(bool enable)
{
_enable = enable;
if (_world != nullptr)
{
if (enable)
{
_world->delayTestAddJoint(this);
}else
{
_world->delayTestRemoveJoint(this);
}
}
}
}
@ -174,6 +180,40 @@ void PhysicsJoint::setCollisionEnable(bool enable)
}
}
void PhysicsJoint::removeFormWorld()
{
if (_world)
{
_world->removeJoint(this, false);
}
}
void PhysicsJoint::destroy(PhysicsJoint* joint)
{
if (joint!= nullptr)
{
// remove the joint and delete it.
if (joint->_world != nullptr)
{
joint->_world->removeJoint(joint, true);
}
else
{
if (joint->_bodyA != nullptr)
{
joint->_bodyA->removeJoint(joint);
}
if (joint->_bodyB != nullptr)
{
joint->_bodyB->removeJoint(joint);
}
delete joint;
}
}
}
PhysicsJointFixed* PhysicsJointFixed::create(PhysicsBody* a, PhysicsBody* b, const Point& anchr)
{
PhysicsJointFixed* joint = new PhysicsJointFixed();

View File

@ -34,6 +34,7 @@
NS_CC_BEGIN
class PhysicsBody;
class PhysicsWorld;
class PhysicsJointInfo;
class PhysicsBodyInfo;
@ -47,14 +48,17 @@ protected:
virtual ~PhysicsJoint() = 0;
public:
PhysicsBody* getBodyA() const { return _bodyA; }
PhysicsBody* getBodyB() const { return _bodyB; }
inline PhysicsBody* getBodyA() const { return _bodyA; }
inline PhysicsBody* getBodyB() const { return _bodyB; }
inline PhysicsWorld* getWorld() const { return _world; }
inline int getTag() const { return _tag; }
inline void setTag(int tag) { _tag = tag; }
inline bool isEnabled() const { return _enable; }
void setEnable(bool enable);
inline bool isCollisionEnabled() const { return _collisionEnable; }
void setCollisionEnable(bool enable);
void removeFormWorld();
static void destroy(PhysicsJoint* joint);
protected:
bool init(PhysicsBody* a, PhysicsBody* b);
@ -68,9 +72,11 @@ protected:
protected:
PhysicsBody* _bodyA;
PhysicsBody* _bodyB;
PhysicsWorld* _world;
PhysicsJointInfo* _info;
bool _enable;
bool _collisionEnable;
bool _destoryMark;
int _tag;
friend class PhysicsBody;

View File

@ -265,7 +265,7 @@ Point PhysicsShape::getPolyonCenter(const Point* points, int count)
void PhysicsShape::setBody(PhysicsBody *body)
{
// already added
if (_body == body)
if (body != nullptr && _body == body)
{
return;
}
@ -278,12 +278,10 @@ void PhysicsShape::setBody(PhysicsBody *body)
if (body == nullptr)
{
_info->setBody(nullptr);
//_info->setGroup(CP_NO_GROUP);
_body = nullptr;
}else
{
_info->setBody(body->_info->getBody());
//_info->setGroup(body->_info->group);
_body = body;
}
}

View File

@ -307,32 +307,82 @@ void PhysicsWorld::delayTestRemoveJoint(PhysicsJoint* joint)
void PhysicsWorld::addJoint(PhysicsJoint* joint)
{
auto it = std::find(_joints.begin(), _joints.end(), joint);
if (it == _joints.end())
{
delayTestAddJoint(joint);
_joints.push_back(joint);
}
joint->_world = this;
}
void PhysicsWorld::removeJoint(PhysicsJoint* joint)
void PhysicsWorld::removeJoint(PhysicsJoint* joint, bool destroy)
{
auto it = std::find(_joints.begin(), _joints.end(), joint);
if (it != _joints.end())
if (joint->getWorld() != this)
{
delayTestRemoveJoint(*it);
if (destroy)
{
CCLOG("physics warnning: the joint is not in this world, it won't be destoried utill the body it conntect is destoried");
}
return;
}
delayTestRemoveJoint(joint);
_joints.remove(joint);
joint->_world = nullptr;
// clean the connection to this joint
if (destroy)
{
if (joint->getBodyA() != nullptr)
{
joint->getBodyA()->removeJoint(joint);
}
if (joint->getBodyB() != nullptr)
{
joint->getBodyB()->removeJoint(joint);
}
// test the distraction is delaied or not
if (_delayRemoveJoints.size() > 0 && _delayRemoveJoints.back() == joint)
{
joint->_destoryMark = true;
}
else
{
delete joint;
}
}
}
void PhysicsWorld::removeAllJoints()
void PhysicsWorld::removeAllJoints(bool destroy)
{
for (auto joint : _joints)
{
delayTestRemoveJoint(joint);
joint->_world = nullptr;
// clean the connection to this joint
if (destroy)
{
if (joint->getBodyA() != nullptr)
{
joint->getBodyA()->removeJoint(joint);
}
if (joint->getBodyB() != nullptr)
{
joint->getBodyB()->removeJoint(joint);
}
// test the distraction is delaied or not
if (_delayRemoveJoints.size() > 0 && _delayRemoveJoints.back() == joint)
{
joint->_destoryMark = true;
}
else
{
delete joint;
}
}
}
_joints.clear();
@ -365,8 +415,6 @@ void PhysicsWorld::realAddBody(PhysicsBody* body)
if (body->isEnabled())
{
body->_world = this;
//is gravity enable
if (!body->isGravityEnabled())
{
@ -393,14 +441,28 @@ PhysicsBody* PhysicsWorld::addBody(PhysicsBody* body)
delayTestAddBody(body);
_bodies->addObject(body);
body->_world = this;
return body;
}
void PhysicsWorld::removeBody(PhysicsBody* body)
{
if (body->getWorld() != this)
{
return;
}
// destory the body's joints
for (auto joint : body->_joints)
{
removeJoint(joint, true);
}
delayTestRemoveBody(body);
_bodies->removeObject(body);
body->_world = nullptr;
}
void PhysicsWorld::removeBody(int tag)
@ -420,23 +482,12 @@ void PhysicsWorld::realRemoveBody(PhysicsBody* body)
{
CCASSERT(body != nullptr, "the body can not be nullptr");
if (body->getWorld() != this)
{
return;
}
// reset the gravity
if (!body->isGravityEnabled())
{
body->applyForce(-_gravity);
}
// remove joints
for (auto joint : body->_joints)
{
removeJoint(joint);
}
// remove shaps
for (auto shape : *body->getShapes())
{
@ -445,8 +496,6 @@ void PhysicsWorld::realRemoveBody(PhysicsBody* body)
// remove body
_info->removeBody(body->_info->getBody());
body->_world = nullptr;
}
void PhysicsWorld::realRemoveJoint(PhysicsJoint* joint)
@ -461,7 +510,9 @@ void PhysicsWorld::removeAllBodies()
{
for (Object* obj : *_bodies)
{
delayTestRemoveBody(dynamic_cast<PhysicsBody*>(obj));
PhysicsBody* child = dynamic_cast<PhysicsBody*>(obj);
delayTestRemoveBody(child);
child->_world = nullptr;
}
_bodies->removeAllObjects();
@ -515,6 +566,11 @@ void PhysicsWorld::updateJoints()
for (auto joint : _delayRemoveJoints)
{
realRemoveJoint(joint);
if (joint->_destoryMark)
{
delete joint;
}
}
_delayAddJoints.clear();
@ -525,8 +581,9 @@ void PhysicsWorld::update(float delta)
{
if (_delayDirty)
{
updateBodies();
// the updateJoints must run before the updateBodies.
updateJoints();
updateBodies();
_delayDirty = !(_delayAddBodies->count() == 0 && _delayRemoveBodies->count() == 0 && _delayAddJoints.size() == 0 && _delayRemoveJoints.size() == 0);
}
@ -795,7 +852,7 @@ void PhysicsWorld::collisionSeparateCallback(PhysicsContact& contact)
_scene->getEventDispatcher()->dispatchEvent(&event);
}
void PhysicsWorld::setGravity(Point gravity)
void PhysicsWorld::setGravity(const Vect& gravity)
{
if (_bodies != nullptr)
{
@ -932,8 +989,8 @@ PhysicsWorld::PhysicsWorld()
PhysicsWorld::~PhysicsWorld()
{
removeAllJoints(true);
removeAllBodies();
removeAllJoints();
CC_SAFE_RELEASE(_delayRemoveBodies);
CC_SAFE_RELEASE(_delayAddBodies);
CC_SAFE_DELETE(_info);

View File

@ -57,7 +57,7 @@ public:
Point start;
Point end;
Point contact;
Point normal;
Vect normal;
float fraction;
void* data;
}Info;
@ -101,9 +101,9 @@ public:
/** Adds a joint to the physics world.*/
virtual void addJoint(PhysicsJoint* joint);
/** Removes a joint from the physics world.*/
virtual void removeJoint(PhysicsJoint* joint);
virtual void removeJoint(PhysicsJoint* joint, bool destroy);
/** Remove all joints from the physics world.*/
virtual void removeAllJoints();
virtual void removeAllJoints(bool destroy);
virtual void removeBody(PhysicsBody* body);
virtual void removeBody(int tag);
@ -123,9 +123,9 @@ public:
inline Scene& getScene() const { return *_scene; }
/** get the gravity value */
inline Point getGravity() const { return _gravity; }
inline Vect getGravity() const { return _gravity; }
/** set the gravity value */
void setGravity(Point gravity);
void setGravity(const Vect& gravity);
/** test the debug draw is enabled */
inline bool isDebugDraw() const { return _debugDraw; }
@ -162,7 +162,7 @@ protected:
virtual void updateJoints();
protected:
Point _gravity;
Vect _gravity;
float _speed;
PhysicsWorldInfo* _info;
@ -187,6 +187,7 @@ protected:
friend class Scene;
friend class PhysicsBody;
friend class PhysicsShape;
friend class PhysicsJoint;
friend class PhysicsWorldCallback;
};