mirror of https://github.com/axmolengine/axmol.git
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:
parent
6c27a0df0b
commit
f2cd5ca630
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -263,6 +263,8 @@ protected:
|
|||
|
||||
virtual void update(float delta) override;
|
||||
|
||||
void removeJoint(PhysicsJoint* joint);
|
||||
|
||||
protected:
|
||||
PhysicsBody();
|
||||
virtual ~PhysicsBody();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue