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

View File

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

View File

@ -32,6 +32,7 @@
#endif #endif
#include "CCPhysicsBody.h" #include "CCPhysicsBody.h"
#include "CCPhysicsWorld.h"
#include "chipmunk/CCPhysicsJointInfo_chipmunk.h" #include "chipmunk/CCPhysicsJointInfo_chipmunk.h"
#include "box2d/CCPhysicsJointInfo_box2d.h" #include "box2d/CCPhysicsJointInfo_box2d.h"
@ -48,9 +49,11 @@ NS_CC_BEGIN
PhysicsJoint::PhysicsJoint() PhysicsJoint::PhysicsJoint()
: _bodyA(nullptr) : _bodyA(nullptr)
, _bodyB(nullptr) , _bodyB(nullptr)
, _world(nullptr)
, _info(nullptr) , _info(nullptr)
, _enable(false) , _enable(false)
, _collisionEnable(true) , _collisionEnable(true)
, _destoryMark(false)
, _tag(0) , _tag(0)
{ {
@ -94,12 +97,15 @@ void PhysicsJoint::setEnable(bool enable)
{ {
_enable = enable; _enable = enable;
if (enable) if (_world != nullptr)
{ {
if (enable)
}else {
{ _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* PhysicsJointFixed::create(PhysicsBody* a, PhysicsBody* b, const Point& anchr)
{ {
PhysicsJointFixed* joint = new PhysicsJointFixed(); PhysicsJointFixed* joint = new PhysicsJointFixed();

View File

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

View File

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

View File

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

View File

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