diff --git a/cocos/physics/CCPhysicsBody.cpp b/cocos/physics/CCPhysicsBody.cpp index 131bfdc3c5..031104157a 100644 --- a/cocos/physics/CCPhysicsBody.cpp +++ b/cocos/physics/CCPhysicsBody.cpp @@ -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); } } } diff --git a/cocos/physics/CCPhysicsBody.h b/cocos/physics/CCPhysicsBody.h index 6ae92e4b33..7f465d561c 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -263,6 +263,8 @@ protected: virtual void update(float delta) override; + void removeJoint(PhysicsJoint* joint); + protected: PhysicsBody(); virtual ~PhysicsBody(); diff --git a/cocos/physics/CCPhysicsJoint.cpp b/cocos/physics/CCPhysicsJoint.cpp index 791266f8ba..38eb106fce 100644 --- a/cocos/physics/CCPhysicsJoint.cpp +++ b/cocos/physics/CCPhysicsJoint.cpp @@ -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 (enable) + if (_world != nullptr) { - - }else - { - + 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(); diff --git a/cocos/physics/CCPhysicsJoint.h b/cocos/physics/CCPhysicsJoint.h index fea8ba4707..55befaf328 100644 --- a/cocos/physics/CCPhysicsJoint.h +++ b/cocos/physics/CCPhysicsJoint.h @@ -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; diff --git a/cocos/physics/CCPhysicsShape.cpp b/cocos/physics/CCPhysicsShape.cpp index 7cc64483cd..05264e6a70 100644 --- a/cocos/physics/CCPhysicsShape.cpp +++ b/cocos/physics/CCPhysicsShape.cpp @@ -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; } } diff --git a/cocos/physics/CCPhysicsWorld.cpp b/cocos/physics/CCPhysicsWorld.cpp index 3c5956b85c..104b916530 100644 --- a/cocos/physics/CCPhysicsWorld.cpp +++ b/cocos/physics/CCPhysicsWorld.cpp @@ -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); - } - + 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); - _joints.remove(joint); + 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(obj)); + PhysicsBody* child = dynamic_cast(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); diff --git a/cocos/physics/CCPhysicsWorld.h b/cocos/physics/CCPhysicsWorld.h index 2e70749f57..65ffd19927 100644 --- a/cocos/physics/CCPhysicsWorld.h +++ b/cocos/physics/CCPhysicsWorld.h @@ -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; };