From 8524a5fb97c17a46722b23b12ef86a52ae4e11ca Mon Sep 17 00:00:00 2001 From: Wenhai Lin Date: Wed, 7 Jan 2015 17:08:04 +0800 Subject: [PATCH] Improve performance of physics --- cocos/2d/CCActionInterval.cpp | 12 - cocos/2d/CCNode.cpp | 249 +++------ cocos/2d/CCNode.h | 15 +- cocos/2d/CCScene.cpp | 17 - cocos/2d/CCScene.h | 1 - cocos/2d/CCSpriteBatchNode.cpp | 11 +- cocos/base/CCDirector.cpp | 17 +- cocos/physics/CCPhysicsBody.cpp | 54 +- cocos/physics/CCPhysicsBody.h | 6 +- cocos/physics/CCPhysicsJoint.cpp | 508 +++++++++--------- cocos/physics/CCPhysicsJoint.h | 161 +++--- cocos/physics/CCPhysicsShape.cpp | 267 ++++----- cocos/physics/CCPhysicsShape.h | 22 +- cocos/physics/CCPhysicsWorld.cpp | 239 +++----- cocos/physics/CCPhysicsWorld.h | 5 +- .../Classes/PhysicsTest/PhysicsTest.cpp | 63 ++- 16 files changed, 670 insertions(+), 977 deletions(-) diff --git a/cocos/2d/CCActionInterval.cpp b/cocos/2d/CCActionInterval.cpp index 48d9f8b3f0..4a03d8064c 100644 --- a/cocos/2d/CCActionInterval.cpp +++ b/cocos/2d/CCActionInterval.cpp @@ -859,12 +859,6 @@ void RotateTo::update(float time) } else { - // _startAngle.x != _startAngle.y || _diffAngle.x != _diffAngle.y - if (_target->getPhysicsBody() != nullptr) - { - CCLOG("RotateTo WARNING: PhysicsBody doesn't support skew rotation"); - } - _target->setRotationSkewX(_startAngle.x + _diffAngle.x * time); _target->setRotationSkewY(_startAngle.y + _diffAngle.y * time); } @@ -1002,12 +996,6 @@ void RotateBy::update(float time) } else { - // _startAngle.x != _startAngle.y || _deltaAngle.x != _deltaAngle.y - if (_target->getPhysicsBody() != nullptr) - { - CCLOG("RotateBy WARNING: PhysicsBody doesn't support skew rotation"); - } - _target->setRotationSkewX(_startAngle.x + _deltaAngle.x * time); _target->setRotationSkewY(_startAngle.y + _deltaAngle.y * time); } diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index f52a1b5a98..3b64b40af5 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -60,7 +60,6 @@ THE SOFTWARE. #define RENDER_IN_SUBPIXEL(__ARGS__) (ceil(__ARGS__)) #endif -extern int g_physicsSceneCount; NS_CC_BEGIN @@ -125,6 +124,8 @@ Node::Node(void) , _physicsBody(nullptr) , _physicsScaleStartX(1.0f) , _physicsScaleStartY(1.0f) +, _physicsRotation(0.0f) +, _physicsTransformDirty(true) #endif , _displayedOpacity(255) , _realOpacity(255) @@ -329,13 +330,6 @@ void Node::setRotation(float rotation) _rotationZ_X = _rotationZ_Y = rotation; _transformUpdated = _transformDirty = _inverseDirty = true; - -#if CC_USE_PHYSICS - if (!_physicsBody || !_physicsBody->_rotationResetTag) - { - updatePhysicsBodyRotation(getScene()); - } -#endif updateRotationQuat(); } @@ -472,16 +466,6 @@ void Node::setScale(float scale) _scaleX = _scaleY = _scaleZ = scale; _transformUpdated = _transformDirty = _inverseDirty = true; - -#if CC_USE_PHYSICS - if(g_physicsSceneCount == 0) - return; - auto scene = getScene(); - if (!scene || scene->getPhysicsWorld()) - { - updatePhysicsBodyTransform(scene); - } -#endif } /// scaleX getter @@ -499,17 +483,6 @@ void Node::setScale(float scaleX,float scaleY) _scaleX = scaleX; _scaleY = scaleY; _transformUpdated = _transformDirty = _inverseDirty = true; - -#if CC_USE_PHYSICS - if(g_physicsSceneCount == 0) - return; - - auto scene = getScene(); - if (!scene || scene->getPhysicsWorld()) - { - updatePhysicsBodyTransform(scene); - } -#endif } /// scaleX setter @@ -520,17 +493,6 @@ void Node::setScaleX(float scaleX) _scaleX = scaleX; _transformUpdated = _transformDirty = _inverseDirty = true; - -#if CC_USE_PHYSICS - if(g_physicsSceneCount == 0) - return; - - auto scene = getScene(); - if (!scene || scene->getPhysicsWorld()) - { - updatePhysicsBodyTransform(scene); - } -#endif } /// scaleY getter @@ -570,17 +532,6 @@ void Node::setScaleY(float scaleY) _scaleY = scaleY; _transformUpdated = _transformDirty = _inverseDirty = true; - -#if CC_USE_PHYSICS - if (g_physicsSceneCount == 0) - return; - - auto scene = getScene(); - if (!scene || scene->getPhysicsWorld()) - { - updatePhysicsBodyTransform(scene); - } -#endif } @@ -612,13 +563,6 @@ void Node::setPosition(float x, float y) _transformUpdated = _transformDirty = _inverseDirty = true; _usingNormalizedPosition = false; - -#if CC_USE_PHYSICS - if (!_physicsBody || !_physicsBody->_positionResetTag) - { - updatePhysicsBodyPosition(getScene()); - } -#endif } void Node::setPosition3D(const Vec3& position) @@ -1076,7 +1020,6 @@ void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::stri auto scene = this->getScene(); if (scene && scene->getPhysicsWorld()) { - child->updatePhysicsBodyTransform(scene); scene->addChildToPhysicsWorld(child); } #endif @@ -1301,6 +1244,12 @@ void Node::visit() uint32_t Node::processParentFlags(const Mat4& parentTransform, uint32_t parentFlags) { +#if CC_USE_PHYSICS + if (_physicsBody && _updateTransformFromPhysics) + { + updateTransformFromPhysics(parentTransform, parentFlags); + } +#endif if(_usingNormalizedPosition) { CCASSERT(_parent, "setNormalizedPosition() doesn't work with orphan nodes"); @@ -2023,87 +1972,6 @@ void Node::removeAllComponents() // MARK: Physics -void Node::updatePhysicsBodyTransform(Scene* scene) -{ - updatePhysicsBodyScale(scene); - updatePhysicsBodyPosition(scene); - updatePhysicsBodyRotation(scene); -} - -void Node::updatePhysicsBodyPosition(Scene* scene) -{ - if (_physicsBody != nullptr) - { - if (scene && scene->getPhysicsWorld()) - { - Vec2 pos = _parent == scene ? _position : scene->convertToNodeSpace(_parent->convertToWorldSpace(_position)); - _physicsBody->setPosition(pos); - } - else - { - _physicsBody->setPosition(_position); - } - } - - for (Node* child : _children) - { - child->updatePhysicsBodyPosition(scene); - } -} - -void Node::updatePhysicsBodyRotation(Scene* scene) -{ - if (_physicsBody != nullptr) - { - if (scene != nullptr && scene->getPhysicsWorld() != nullptr) - { - float rotation = _rotationZ_X; - for (Node* parent = _parent; parent != scene; parent = parent->_parent) - { - rotation += parent->getRotation(); - } - _physicsBody->setRotation(rotation); - } - else - { - _physicsBody->setRotation(_rotationZ_X); - } - } - - for (auto child : _children) - { - child->updatePhysicsBodyRotation(scene); - child->updatePhysicsBodyPosition(scene); - } -} - -void Node::updatePhysicsBodyScale(Scene* scene) -{ - if (_physicsBody != nullptr) - { - if (scene != nullptr && scene->getPhysicsWorld() != nullptr) - { - float scaleX = _scaleX / _physicsScaleStartX; - float scaleY = _scaleY / _physicsScaleStartY; - for (Node* parent = _parent; parent != scene; parent = parent->_parent) - { - scaleX *= parent->_scaleX; - scaleY *= parent->_scaleY; - } - _physicsBody->setScale(scaleX, scaleY); - } - else - { - _physicsBody->setScale(_scaleX / _physicsScaleStartX, _scaleY / _physicsScaleStartY); - } - } - - for (const auto& child : _children) - { - child->updatePhysicsBodyScale(scene); - } -} - void Node::setPhysicsBody(PhysicsBody* body) { if (_physicsBody == body) @@ -2111,9 +1979,17 @@ void Node::setPhysicsBody(PhysicsBody* body) return; } - if (body != nullptr) + if (_physicsBody) { - if (body->getNode() != nullptr) + _physicsBody->removeFromWorld(); + _physicsBody->_node = nullptr; + _physicsBody->release(); + _physicsBody = nullptr; + } + + if (body) + { + if (body->getNode()) { body->getNode()->setPhysicsBody(nullptr); } @@ -2128,52 +2004,65 @@ void Node::setPhysicsBody(PhysicsBody* body) CCLOG("Node warning: setPhysicsBody sets anchor point to Vec2::ANCHOR_MIDDLE."); setAnchorPoint(Vec2::ANCHOR_MIDDLE); } - } - - if (_physicsBody != nullptr) - { - PhysicsWorld* world = _physicsBody->getWorld(); - _physicsBody->removeFromWorld(); - _physicsBody->_node = nullptr; - _physicsBody->release(); - - if (world != nullptr && body != nullptr) - { - world->addBody(body); - } - } - - _physicsBody = body; - _physicsScaleStartX = _scaleX; - _physicsScaleStartY = _scaleY; - - if (body != nullptr) - { - Node* node; - Scene* scene = nullptr; - for (node = this->getParent(); node != nullptr; node = node->getParent()) - { - Scene* tmpScene = dynamic_cast(node); - if (tmpScene != nullptr && tmpScene->getPhysicsWorld() != nullptr) - { - scene = tmpScene; - break; - } - } - - if (scene != nullptr) + + _physicsBody = body; + _physicsScaleStartX = _scaleX; + _physicsScaleStartY = _scaleY; + + auto scene = getScene(); + if (scene && scene->getPhysicsWorld()) { + _physicsTransformDirty = true; scene->getPhysicsWorld()->addBody(body); } - - updatePhysicsBodyTransform(scene); } } -PhysicsBody* Node::getPhysicsBody() const +void Node::updatePhysicsBodyTransform(Scene* scene, const Mat4& parentTransform, uint32_t parentFlags, float parentScaleX, float parentScaleY) { - return _physicsBody; + _updateTransformFromPhysics = false; + auto flags = processParentFlags(parentTransform, parentFlags); + _updateTransformFromPhysics = true; + auto scaleX = parentScaleX * _scaleX; + auto scaleY = parentScaleY * _scaleY; + + if (_parent) + { + _physicsRotation = _parent->_physicsRotation + _rotationZ_X; + } + if (_physicsBody && ((flags & FLAGS_DIRTY_MASK) || _physicsTransformDirty)) + { + _physicsTransformDirty = false; + Vec3 vec3(_position.x, _position.y, 0); + Vec3 ret; + parentTransform.transformPoint(vec3, &ret); + _physicsBody->setPosition(Vec2(ret.x, ret.y)); + _physicsBody->setScale(scaleX / _physicsScaleStartX, scaleY / _physicsScaleStartY); + _physicsBody->setRotation(_physicsRotation); + } + + for (auto node : _children) + { + node->updatePhysicsBodyTransform(scene, _modelViewTransform, flags, scaleX, scaleY); + } } + +void Node::updateTransformFromPhysics(const Mat4& parentTransform, uint32_t parentFlags) +{ + auto newPos = _physicsBody->getPosition(); + auto& recordPos = _physicsBody->_recordPosition; + if (parentFlags || recordPos.x != newPos.x || recordPos.y != newPos.y) + { + recordPos = newPos; + Vec3 vec3(newPos.x, newPos.y, 0); + Vec3 ret; + parentTransform.getInversed().transformPoint(vec3, &ret); + setPosition(ret.x, ret.y); + } + _physicsRotation = _physicsBody->getRotation(); + setRotation(_physicsRotation - _parent->_physicsRotation); +} + #endif //CC_USE_PHYSICS // MARK: Opacity and Color diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index 84d26dba42..935e6d6bc8 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1532,13 +1532,16 @@ public: /** * get the PhysicsBody the sprite have */ - PhysicsBody* getPhysicsBody() const; + PhysicsBody* getPhysicsBody() const { return _physicsBody; } /** * remove this node from physics world. it will remove all the physics bodies in it's children too. */ void removeFromPhysicsWorld(); + + void updateTransformFromPhysics(const Mat4& parentTransform, uint32_t parentFlags); + virtual void updatePhysicsBodyTransform(Scene* scene, const Mat4& parentTransform, uint32_t parentFlags, float parentScaleX, float parentScaleY); #endif // overrides @@ -1612,13 +1615,6 @@ protected: // update Rotation3D from quaternion void updateRotation3D(); -#if CC_USE_PHYSICS - void updatePhysicsBodyTransform(Scene* layer); - virtual void updatePhysicsBodyPosition(Scene* layer); - virtual void updatePhysicsBodyRotation(Scene* layer); - virtual void updatePhysicsBodyScale(Scene* scene); -#endif // CC_USE_PHYSICS - private: void addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag); @@ -1709,6 +1705,9 @@ protected: PhysicsBody* _physicsBody; ///< the physicsBody the node have float _physicsScaleStartX; ///< the scale x value when setPhysicsBody float _physicsScaleStartY; ///< the scale y value when setPhysicsBody + float _physicsRotation; + bool _physicsTransformDirty; + bool _updateTransformFromPhysics; #endif // opacity controls diff --git a/cocos/2d/CCScene.cpp b/cocos/2d/CCScene.cpp index 0d1cf2c182..c3adab81b9 100644 --- a/cocos/2d/CCScene.cpp +++ b/cocos/2d/CCScene.cpp @@ -37,8 +37,6 @@ THE SOFTWARE. #include "physics/CCPhysicsWorld.h" #endif -int g_physicsSceneCount = 0; - NS_CC_BEGIN Scene::Scene() @@ -60,10 +58,6 @@ Scene::Scene() Scene::~Scene() { #if CC_USE_PHYSICS - if (_physicsWorld) - { - g_physicsSceneCount--; - } CC_SAFE_DELETE(_physicsWorld); #endif Director::getInstance()->getEventDispatcher()->removeEventListener(_event); @@ -177,15 +171,6 @@ void Scene::addChild(Node* child, int zOrder, const std::string &name) addChildToPhysicsWorld(child); } -void Scene::update(float delta) -{ - Node::update(delta); - if (nullptr != _physicsWorld && _physicsWorld->isAutoStep()) - { - _physicsWorld->update(delta); - } -} - Scene* Scene::createWithPhysics() { Scene *ret = new (std::nothrow) Scene(); @@ -212,9 +197,7 @@ bool Scene::initWithPhysics() this->setContentSize(director->getWinSize()); CC_BREAK_IF(! (_physicsWorld = PhysicsWorld::construct(*this))); - this->scheduleUpdate(); // success - g_physicsSceneCount += 1; ret = true; } while (0); return ret; diff --git a/cocos/2d/CCScene.h b/cocos/2d/CCScene.h index 058dd051b0..9f0d6d9478 100644 --- a/cocos/2d/CCScene.h +++ b/cocos/2d/CCScene.h @@ -108,7 +108,6 @@ private: public: virtual void addChild(Node* child, int zOrder, int tag) override; virtual void addChild(Node* child, int zOrder, const std::string &name) override; - virtual void update(float delta) override; inline PhysicsWorld* getPhysicsWorld() { return _physicsWorld; } static Scene *createWithPhysics(); diff --git a/cocos/2d/CCSpriteBatchNode.cpp b/cocos/2d/CCSpriteBatchNode.cpp index f74948d72d..ec1a6d1cf7 100644 --- a/cocos/2d/CCSpriteBatchNode.cpp +++ b/cocos/2d/CCSpriteBatchNode.cpp @@ -366,8 +366,17 @@ void SpriteBatchNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t f return; } - for(const auto &child: _children) + for (const auto &child : _children) + { +#if CC_USE_PHYSICS + auto physicsBody = child->getPhysicsBody(); + if (physicsBody) + { + child->updateTransformFromPhysics(transform, flags); + } +#endif child->updateTransform(); + } _batchCommand.init( _globalZOrder, diff --git a/cocos/base/CCDirector.cpp b/cocos/base/CCDirector.cpp index ab4db8fd3c..fc3fa2d9ce 100644 --- a/cocos/base/CCDirector.cpp +++ b/cocos/base/CCDirector.cpp @@ -65,6 +65,10 @@ THE SOFTWARE. #include "CCScriptSupport.h" #endif +#if CC_USE_PHYSICS +#include "physics/CCPhysicsWorld.h" +#endif + /** Position of the FPS @@ -265,12 +269,6 @@ void Director::drawScene() // calculate "global" dt calculateDeltaTime(); - // skip one flame when _deltaTime equal to zero. - if(_deltaTime < FLT_EPSILON) - { - return; - } - if (_openGLView) { _openGLView->pollEvents(); @@ -297,6 +295,13 @@ void Director::drawScene() if (_runningScene) { +#if CC_USE_PHYSICS + auto physicsWorld = _runningScene->getPhysicsWorld(); + if (physicsWorld && physicsWorld->isAutoStep()) + { + physicsWorld->update(_deltaTime, false); + } +#endif //clear draw stats _renderer->clearDrawStats(); diff --git a/cocos/physics/CCPhysicsBody.cpp b/cocos/physics/CCPhysicsBody.cpp index 75183606eb..04ea19575e 100644 --- a/cocos/physics/CCPhysicsBody.cpp +++ b/cocos/physics/CCPhysicsBody.cpp @@ -68,9 +68,8 @@ PhysicsBody::PhysicsBody() , _linearDamping(0.0f) , _angularDamping(0.0f) , _tag(0) -, _positionResetTag(false) -, _rotationResetTag(false) , _rotationOffset(0) +, _recordPosition(Vec2::ZERO) { } @@ -333,6 +332,7 @@ void PhysicsBody::setGravityEnable(bool enable) void PhysicsBody::setPosition(const Vec2& position) { + _recordPosition = position; cpBodySetPos(_cpBody, PhysicsHelper::point2cpv(position + _positionOffset)); } @@ -341,14 +341,6 @@ void PhysicsBody::setRotation(float rotation) cpBodySetAngle(_cpBody, -PhysicsHelper::float2cpfloat((rotation + _rotationOffset) * (M_PI / 180.0f))); } -void PhysicsBody::setScale(float scale) -{ - for (auto shape : _shapes) - { - shape->setScale(scale); - } -} - void PhysicsBody::setScale(float scaleX, float scaleY) { for (auto shape : _shapes) @@ -357,22 +349,6 @@ void PhysicsBody::setScale(float scaleX, float scaleY) } } -void PhysicsBody::setScaleX(float scaleX) -{ - for (auto shape : _shapes) - { - shape->setScaleX(scaleX); - } -} - -void PhysicsBody::setScaleY(float scaleY) -{ - for (auto shape : _shapes) - { - shape->setScaleY(scaleY); - } -} - Vec2 PhysicsBody::getPosition() const { cpVect vec = cpBodyGetPos(_cpBody); @@ -402,7 +378,7 @@ PhysicsShape* PhysicsBody::addShape(PhysicsShape* shape, bool addMassAndMoment/* addMoment(shape->getMoment()); } - if (_world != nullptr) + if (_world && _cpBody->CP_PRIVATE(space)) { _world->addShape(shape); } @@ -764,30 +740,8 @@ void PhysicsBody::setResting(bool rest) const void PhysicsBody::update(float delta) { - if (_node != nullptr) + if (_node) { - for (auto shape : _shapes) - { - shape->update(delta); - } - - Node* parent = _node->getParent(); - Node* scene = &_world->getScene(); - - Vec2 position = parent != scene ? parent->convertToNodeSpace(scene->convertToWorldSpace(getPosition())) : getPosition(); - float rotation = getRotation(); - for (; parent != scene; parent = parent->getParent()) - { - rotation -= parent->getRotation(); - } - - _positionResetTag = true; - _rotationResetTag = true; - _node->setPosition(position); - _node->setRotation(rotation); - _positionResetTag = false; - _rotationResetTag = false; - // damping compute if (_isDamping && _dynamic && !isResting()) { diff --git a/cocos/physics/CCPhysicsBody.h b/cocos/physics/CCPhysicsBody.h index 8b4babe4cf..20a53befc8 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -306,10 +306,7 @@ protected: virtual void setPosition(const Vec2& position); virtual void setRotation(float rotation); - virtual void setScale(float scale); virtual void setScale(float scaleX, float scaleY); - virtual void setScaleX(float scaleX); - virtual void setScaleY(float scaleY); void update(float delta); @@ -341,8 +338,7 @@ protected: float _angularDamping; int _tag; - bool _positionResetTag; /// To avoid reset the body position when body invoke Node::setPosition(). - bool _rotationResetTag; /// To avoid reset the body rotation when body invoke Node::setRotation(). + Vec2 _recordPosition; Vec2 _positionOffset; float _rotationOffset; diff --git a/cocos/physics/CCPhysicsJoint.cpp b/cocos/physics/CCPhysicsJoint.cpp index b9628ca88c..5caa38c68a 100644 --- a/cocos/physics/CCPhysicsJoint.cpp +++ b/cocos/physics/CCPhysicsJoint.cpp @@ -40,20 +40,23 @@ PhysicsJoint::PhysicsJoint() , _enable(false) , _collisionEnable(true) , _destoryMark(false) +, _initDirty(true) , _tag(0) +, _maxForce(PHYSICS_INFINITY) { - + } PhysicsJoint::~PhysicsJoint() { // reset the shapes collision group setCollisionEnable(true); - - for (auto constraint : _cpConstraints) + + for (cpConstraint* joint : _cpConstraints) { - cpConstraintFree(constraint); + cpConstraintFree(joint); } + _cpConstraints.clear(); } bool PhysicsJoint::init(cocos2d::PhysicsBody *a, cocos2d::PhysicsBody *b) @@ -62,42 +65,59 @@ bool PhysicsJoint::init(cocos2d::PhysicsBody *a, cocos2d::PhysicsBody *b) { CCASSERT(a != nullptr && b != nullptr, "the body passed in is nil"); CCASSERT(a != b, "the two bodies are equal"); - + _bodyA = a; - _bodyA->_joints.push_back(this); _bodyB = b; + _bodyA->_joints.push_back(this); _bodyB->_joints.push_back(this); - + return true; } while (false); - + return false; } +bool PhysicsJoint::initJoint() +{ + bool ret = !_initDirty; + while (_initDirty) + { + ret = createConstraints(); + CC_BREAK_IF(!ret); + + for (auto subjoint : _cpConstraints) + { + subjoint->maxForce = _maxForce; + subjoint->errorBias = cpfpow(1.0f - 0.15f, 60.0f); + cpSpaceAddConstraint(_world->_cpSpace, subjoint); + } + _initDirty = false; + ret = true; + } + + return ret; +} + void PhysicsJoint::setEnable(bool enable) { if (_enable != enable) { _enable = enable; - - if (_world != nullptr) + + if (_world) { if (enable) { - _world->addJointOrDelay(this); - }else + _world->addJoint(this); + } + else { - _world->removeJointOrDelay(this); + _world->removeJoint(this, false); } } } } -Node* PhysicsJoint::getBodyNode(PhysicsBody* body) const -{ - return body->_node; -} - void PhysicsJoint::setCollisionEnable(bool enable) { if (_collisionEnable != enable) @@ -114,126 +134,126 @@ void PhysicsJoint::removeFormWorld() } } -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; - } - } -} - void PhysicsJoint::setMaxForce(float force) { + _maxForce = force; for (auto joint : _cpConstraints) { joint->maxForce = PhysicsHelper::float2cpfloat(force); } } -float PhysicsJoint::getMaxForce() const -{ - return PhysicsHelper::cpfloat2float(_cpConstraints.front()->maxForce); -} - PhysicsJointFixed* PhysicsJointFixed::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr) { - PhysicsJointFixed* joint = new (std::nothrow) PhysicsJointFixed(); - - if (joint && joint->init(a, b, anchr)) + auto joint = new (std::nothrow) PhysicsJointFixed(); + + if (joint && joint->init(a, b)) { + joint->_anchr = anchr; return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointFixed::init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr) +bool PhysicsJointFixed::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - getBodyNode(a)->setPosition(anchr); - getBodyNode(b)->setPosition(anchr); - + _bodyA->getNode()->setPosition(_anchr); + _bodyB->getNode()->setPosition(_anchr); + // add a pivot joint to fixed two body together - auto constraint = cpPivotJointNew(a->getCPBody(), b->getCPBody(), - PhysicsHelper::point2cpv(anchr)); - CC_BREAK_IF(constraint == nullptr); - _cpConstraints.push_back(constraint); - + auto joint = cpPivotJointNew(_bodyA->getCPBody(), _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr)); + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + // add a gear joint to make two body have the same rotation. - constraint = cpGearJointNew(a->getCPBody(), b->getCPBody(), 0, 1); - CC_BREAK_IF(constraint == nullptr); - _cpConstraints.push_back(constraint); - - setCollisionEnable(false); - + joint = cpGearJointNew(_bodyA->getCPBody(), _bodyB->getCPBody(), 0, 1); + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + + _collisionEnable = false; + return true; } while (false); - + return false; } -PhysicsJointPin* PhysicsJointPin::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr) +PhysicsJointPin* PhysicsJointPin::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& pivot) { - PhysicsJointPin* joint = new (std::nothrow) PhysicsJointPin(); - - if (joint && joint->init(a, b, anchr)) + auto joint = new (std::nothrow) PhysicsJointPin(); + + if (joint && joint->init(a, b)) { + joint->_anchr1 = pivot; + joint->_useSpecificAnchr = false; return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointPin::init(PhysicsBody *a, PhysicsBody *b, const Vec2& anchr) +PhysicsJointPin* PhysicsJointPin::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2) +{ + auto joint = new (std::nothrow) PhysicsJointPin(); + + if (joint && joint->init(a, b)) + { + joint->_anchr1 = anchr1; + joint->_anchr2 = anchr2; + joint->_useSpecificAnchr = true; + + return joint; + } + + CC_SAFE_DELETE(joint); + return nullptr; +} + +bool PhysicsJointPin::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - auto constraint = cpPivotJointNew(a->getCPBody(), b->getCPBody(), - PhysicsHelper::point2cpv(anchr)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + cpConstraint* joint = nullptr; + if (_useSpecificAnchr) + { + joint = cpPivotJointNew2(_bodyA->getCPBody(), _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr1), PhysicsHelper::point2cpv(_anchr2)); + } + else + { + joint = cpPivotJointNew(_bodyA->getCPBody(), _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr1)); + } + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } PhysicsJointLimit* PhysicsJointLimit::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float min, float max) { - PhysicsJointLimit* joint = new (std::nothrow) PhysicsJointLimit(); - - if (joint && joint->init(a, b, anchr1, anchr2, min, max)) + auto joint = new (std::nothrow) PhysicsJointLimit(); + + if (joint && joint->init(a, b)) { + joint->_anchr1 = anchr1; + joint->_anchr2 = anchr2; + joint->_min = min; + joint->_max = max; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } @@ -243,25 +263,22 @@ PhysicsJointLimit* PhysicsJointLimit::construct(PhysicsBody* a, PhysicsBody* b, return construct(a, b, anchr1, anchr2, 0, b->local2World(anchr1).getDistance(a->local2World(anchr2))); } -bool PhysicsJointLimit::init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float min, float max) +bool PhysicsJointLimit::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpSlideJointNew(a->getCPBody(), b->getCPBody(), - PhysicsHelper::point2cpv(anchr1), - PhysicsHelper::point2cpv(anchr2), - PhysicsHelper::float2cpfloat(min), - PhysicsHelper::float2cpfloat(max)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpSlideJointNew(_bodyA->getCPBody(), _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr1), + PhysicsHelper::point2cpv(_anchr2), + PhysicsHelper::float2cpfloat(_min), + PhysicsHelper::float2cpfloat(_max)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -307,35 +324,34 @@ void PhysicsJointLimit::setAnchr2(const Vec2& anchr) PhysicsJointDistance* PhysicsJointDistance::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2) { - PhysicsJointDistance* joint = new (std::nothrow) PhysicsJointDistance(); - - if (joint && joint->init(a, b, anchr1, anchr2)) + auto joint = new (std::nothrow) PhysicsJointDistance(); + + if (joint && joint->init(a, b)) { + joint->_anchr1 = anchr1; + joint->_anchr2 = anchr2; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointDistance::init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2) +bool PhysicsJointDistance::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpPinJointNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::point2cpv(anchr1), - PhysicsHelper::point2cpv(anchr2)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpPinJointNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr1), + PhysicsHelper::point2cpv(_anchr2)); + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -351,37 +367,39 @@ void PhysicsJointDistance::setDistance(float distance) PhysicsJointSpring* PhysicsJointSpring::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float stiffness, float damping) { - PhysicsJointSpring* joint = new (std::nothrow) PhysicsJointSpring(); - - if (joint && joint->init(a, b, anchr1, anchr2, stiffness, damping)) + auto joint = new (std::nothrow) PhysicsJointSpring(); + + if (joint && joint->init(a, b)) { + joint->_anchr1 = anchr1; + joint->_anchr2 = anchr2; + joint->_stiffness = stiffness; + joint->_damping = damping; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointSpring::init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float stiffness, float damping) +bool PhysicsJointSpring::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpDampedSpringNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::point2cpv(anchr1), - PhysicsHelper::point2cpv(anchr2), - PhysicsHelper::float2cpfloat(_bodyB->local2World(anchr1).getDistance(_bodyA->local2World(anchr2))), - PhysicsHelper::float2cpfloat(stiffness), - PhysicsHelper::float2cpfloat(damping)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpDampedSpringNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_anchr1), + PhysicsHelper::point2cpv(_anchr2), + PhysicsHelper::float2cpfloat(_bodyB->local2World(_anchr1).getDistance(_bodyA->local2World(_anchr2))), + PhysicsHelper::float2cpfloat(_stiffness), + PhysicsHelper::float2cpfloat(_damping)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -437,35 +455,36 @@ void PhysicsJointSpring::setDamping(float damping) PhysicsJointGroove* PhysicsJointGroove::construct(PhysicsBody* a, PhysicsBody* b, const Vec2& grooveA, const Vec2& grooveB, const Vec2& anchr2) { - PhysicsJointGroove* joint = new (std::nothrow) PhysicsJointGroove(); - - if (joint && joint->init(a, b, grooveA, grooveB, anchr2)) + auto joint = new (std::nothrow) PhysicsJointGroove(); + + if (joint && joint->init(a, b)) { + joint->_grooveA = grooveA; + joint->_grooveB = grooveB; + joint->_anchr2 = anchr2; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointGroove::init(PhysicsBody* a, PhysicsBody* b, const Vec2& grooveA, const Vec2& grooveB, const Vec2& anchr2) +bool PhysicsJointGroove::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpGrooveJointNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::point2cpv(grooveA), - PhysicsHelper::point2cpv(grooveB), - PhysicsHelper::point2cpv(anchr2)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpGrooveJointNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::point2cpv(_grooveA), + PhysicsHelper::point2cpv(_grooveB), + PhysicsHelper::point2cpv(_anchr2)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -501,35 +520,35 @@ void PhysicsJointGroove::setAnchr2(const Vec2& anchr2) PhysicsJointRotarySpring* PhysicsJointRotarySpring::construct(PhysicsBody* a, PhysicsBody* b, float stiffness, float damping) { - PhysicsJointRotarySpring* joint = new (std::nothrow) PhysicsJointRotarySpring(); - - if (joint && joint->init(a, b, stiffness, damping)) + auto joint = new (std::nothrow) PhysicsJointRotarySpring(); + + if (joint && joint->init(a, b)) { + joint->_stiffness = stiffness; + joint->_damping = damping; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointRotarySpring::init(PhysicsBody* a, PhysicsBody* b, float stiffness, float damping) +bool PhysicsJointRotarySpring::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpDampedRotarySpringNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::float2cpfloat(_bodyB->getRotation() - _bodyA->getRotation()), - PhysicsHelper::float2cpfloat(stiffness), - PhysicsHelper::float2cpfloat(damping)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpDampedRotarySpringNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::float2cpfloat(_bodyB->getRotation() - _bodyA->getRotation()), + PhysicsHelper::float2cpfloat(_stiffness), + PhysicsHelper::float2cpfloat(_damping)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -565,13 +584,16 @@ void PhysicsJointRotarySpring::setDamping(float damping) PhysicsJointRotaryLimit* PhysicsJointRotaryLimit::construct(PhysicsBody* a, PhysicsBody* b, float min, float max) { - PhysicsJointRotaryLimit* joint = new (std::nothrow) PhysicsJointRotaryLimit(); - - if (joint && joint->init(a, b, min, max)) + auto joint = new (std::nothrow) PhysicsJointRotaryLimit(); + + if (joint && joint->init(a, b)) { + joint->_min = min; + joint->_max = max; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } @@ -581,24 +603,21 @@ PhysicsJointRotaryLimit* PhysicsJointRotaryLimit::construct(PhysicsBody* a, Phys return construct(a, b, 0.0f, 0.0f); } -bool PhysicsJointRotaryLimit::init(PhysicsBody* a, PhysicsBody* b, float min, float max) +bool PhysicsJointRotaryLimit::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpRotaryLimitJointNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::float2cpfloat(min), - PhysicsHelper::float2cpfloat(max)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpRotaryLimitJointNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::float2cpfloat(_min), + PhysicsHelper::float2cpfloat(_max)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -624,35 +643,35 @@ void PhysicsJointRotaryLimit::setMax(float max) PhysicsJointRatchet* PhysicsJointRatchet::construct(PhysicsBody* a, PhysicsBody* b, float phase, float ratchet) { - PhysicsJointRatchet* joint = new (std::nothrow) PhysicsJointRatchet(); - - if (joint && joint->init(a, b, phase, ratchet)) + auto joint = new (std::nothrow) PhysicsJointRatchet(); + + if (joint && joint->init(a, b)) { + joint->_phase = phase; + joint->_ratchet = ratchet; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointRatchet::init(PhysicsBody* a, PhysicsBody* b, float phase, float ratchet) +bool PhysicsJointRatchet::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpRatchetJointNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::float2cpfloat(phase), - PhysicsHelper::cpfloat2float(ratchet)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpRatchetJointNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::float2cpfloat(_phase), + PhysicsHelper::cpfloat2float(_ratchet)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -686,37 +705,37 @@ void PhysicsJointRatchet::setRatchet(float ratchet) cpRatchetJointSetRatchet(_cpConstraints.front(), PhysicsHelper::float2cpfloat(ratchet)); } -PhysicsJointGear* PhysicsJointGear::construct(PhysicsBody* a, PhysicsBody* b, float phase, float ratchet) +PhysicsJointGear* PhysicsJointGear::construct(PhysicsBody* a, PhysicsBody* b, float phase, float ratio) { - PhysicsJointGear* joint = new (std::nothrow) PhysicsJointGear(); - - if (joint && joint->init(a, b, phase, ratchet)) + auto joint = new (std::nothrow) PhysicsJointGear(); + + if (joint && joint->init(a, b)) { + joint->_phase = phase; + joint->_ratio = ratio; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointGear::init(PhysicsBody* a, PhysicsBody* b, float phase, float ratio) +bool PhysicsJointGear::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpGearJointNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::float2cpfloat(phase), - PhysicsHelper::float2cpfloat(ratio)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpGearJointNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::float2cpfloat(_phase), + PhysicsHelper::float2cpfloat(_ratio)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } @@ -742,34 +761,33 @@ void PhysicsJointGear::setRatio(float ratio) PhysicsJointMotor* PhysicsJointMotor::construct(PhysicsBody* a, PhysicsBody* b, float rate) { - PhysicsJointMotor* joint = new (std::nothrow) PhysicsJointMotor(); - - if (joint && joint->init(a, b, rate)) + auto joint = new (std::nothrow) PhysicsJointMotor(); + + if (joint && joint->init(a, b)) { + joint->_rate = rate; + return joint; } - + CC_SAFE_DELETE(joint); return nullptr; } -bool PhysicsJointMotor::init(PhysicsBody* a, PhysicsBody* b, float rate) +bool PhysicsJointMotor::createConstraints() { do { - CC_BREAK_IF(!PhysicsJoint::init(a, b)); - - auto constraint = cpSimpleMotorNew(a->getCPBody(), - b->getCPBody(), - PhysicsHelper::float2cpfloat(rate)); - - CC_BREAK_IF(constraint == nullptr); - - _cpConstraints.push_back(constraint); - + auto joint = cpSimpleMotorNew(_bodyA->getCPBody(), + _bodyB->getCPBody(), + PhysicsHelper::float2cpfloat(_rate)); + + CC_BREAK_IF(joint == nullptr); + _cpConstraints.push_back(joint); + return true; } while (false); - + return false; } diff --git a/cocos/physics/CCPhysicsJoint.h b/cocos/physics/CCPhysicsJoint.h index 6fcb53f96c..523b4b5662 100644 --- a/cocos/physics/CCPhysicsJoint.h +++ b/cocos/physics/CCPhysicsJoint.h @@ -62,58 +62,62 @@ public: void setCollisionEnable(bool enable); /** Remove the joint from the world */ void removeFormWorld(); - /** Distory the joint*/ - static void destroy(PhysicsJoint* joint); - + /** Set the max force between two bodies */ void setMaxForce(float force); /** Get the max force setting */ - float getMaxForce() const; - + float getMaxForce() const { return _maxForce; } + protected: bool init(PhysicsBody* a, PhysicsBody* b); - Node* getBodyNode(PhysicsBody* body) const; - -protected: + + bool initJoint(); + virtual bool createConstraints() { return false; } + + std::vector _cpConstraints; PhysicsBody* _bodyA; PhysicsBody* _bodyB; PhysicsWorld* _world; - std::vector _cpConstraints; + bool _enable; bool _collisionEnable; bool _destoryMark; int _tag; - + float _maxForce; + + bool _initDirty; + friend class PhysicsBody; friend class PhysicsWorld; friend class PhysicsDebugDraw; }; /* - * @brief A fixed joint fuses the two bodies together at a reference point. Fixed joints are useful for creating complex shapes that can be broken apart later. - */ +* @brief A fixed joint fuses the two bodies together at a reference point. Fixed joints are useful for creating complex shapes that can be broken apart later. +*/ class CC_DLL PhysicsJointFixed : public PhysicsJoint { public: static PhysicsJointFixed* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr); - + + virtual bool createConstraints() override; + protected: PhysicsJointFixed() {} virtual ~PhysicsJointFixed() {} + + Vec2 _anchr; }; /* - * @brief A limit joint imposes a maximum distance between the two bodies, as if they were connected by a rope. - */ +* @brief A limit joint imposes a maximum distance between the two bodies, as if they were connected by a rope. +*/ class CC_DLL PhysicsJointLimit : public PhysicsJoint { public: static PhysicsJointLimit* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2); static PhysicsJointLimit* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float min, float max); - + Vec2 getAnchr1() const; void setAnchr1(const Vec2& anchr1); Vec2 getAnchr2() const; @@ -122,29 +126,37 @@ public: void setMin(float min); float getMax() const; void setMax(float max); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float min, float max); - + + virtual bool createConstraints() override; + protected: PhysicsJointLimit() {} virtual ~PhysicsJointLimit() {} + + Vec2 _anchr1; + Vec2 _anchr2; + float _min; + float _max; }; /* - * @brief A pin joint allows the two bodies to independently rotate around the anchor point as if pinned together. - */ +* @brief A pin joint allows the two bodies to independently rotate around the anchor point as if pinned together. +*/ class CC_DLL PhysicsJointPin : public PhysicsJoint { public: - static PhysicsJointPin* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr); - + static PhysicsJointPin* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& pivot); + static PhysicsJointPin* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2); + + virtual bool createConstraints() override; + protected: PhysicsJointPin() {} virtual ~PhysicsJointPin() {} + + bool _useSpecificAnchr; + Vec2 _anchr1; + Vec2 _anchr2; }; /** Set the fixed distance with two bodies */ @@ -152,16 +164,17 @@ class CC_DLL PhysicsJointDistance : public PhysicsJoint { public: static PhysicsJointDistance* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2); - + float getDistance() const; void setDistance(float distance); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2); - + virtual bool createConstraints() override; + protected: PhysicsJointDistance() {} virtual ~PhysicsJointDistance() {} + + Vec2 _anchr1; + Vec2 _anchr2; }; /** Connecting two physics bodies together with a spring. */ @@ -179,13 +192,16 @@ public: void setStiffness(float stiffness); float getDamping() const; void setDamping(float damping); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& anchr1, const Vec2& anchr2, float stiffness, float damping); - + virtual bool createConstraints() override; + protected: PhysicsJointSpring() {} virtual ~PhysicsJointSpring() {} + + Vec2 _anchr1; + Vec2 _anchr2; + float _stiffness; + float _damping; }; /** Attach body a to a line, and attach body b to a dot */ @@ -193,20 +209,22 @@ class CC_DLL PhysicsJointGroove : public PhysicsJoint { public: static PhysicsJointGroove* construct(PhysicsBody* a, PhysicsBody* b, const Vec2& grooveA, const Vec2& grooveB, const Vec2& anchr2); - + Vec2 getGrooveA() const; void setGrooveA(const Vec2& grooveA); Vec2 getGrooveB() const; void setGrooveB(const Vec2& grooveB); Vec2 getAnchr2() const; void setAnchr2(const Vec2& anchr2); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, const Vec2& grooveA, const Vec2& grooveB, const Vec2& anchr); - + virtual bool createConstraints() override; + protected: PhysicsJointGroove() {} virtual ~PhysicsJointGroove() {} + + Vec2 _grooveA; + Vec2 _grooveB; + Vec2 _anchr2; }; /** Likes a spring joint, but works with rotary */ @@ -214,20 +232,21 @@ class CC_DLL PhysicsJointRotarySpring : public PhysicsJoint { public: static PhysicsJointRotarySpring* construct(PhysicsBody* a, PhysicsBody* b, float stiffness, float damping); - + float getRestAngle() const; void setRestAngle(float restAngle); float getStiffness() const; void setStiffness(float stiffness); float getDamping() const; void setDamping(float damping); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, float stiffness, float damping); - + virtual bool createConstraints() override; + protected: PhysicsJointRotarySpring() {} virtual ~PhysicsJointRotarySpring() {} + + float _stiffness; + float _damping; }; /** Likes a limit joint, but works with rotary */ @@ -236,18 +255,19 @@ class CC_DLL PhysicsJointRotaryLimit : public PhysicsJoint public: static PhysicsJointRotaryLimit* construct(PhysicsBody* a, PhysicsBody* b, float min, float max); static PhysicsJointRotaryLimit* construct(PhysicsBody* a, PhysicsBody* b); - + float getMin() const; void setMin(float min); float getMax() const; void setMax(float max); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, float min, float max); - + virtual bool createConstraints() override; + protected: PhysicsJointRotaryLimit() {} virtual ~PhysicsJointRotaryLimit() {} + + float _min; + float _max; }; /** Works like a socket wrench. */ @@ -255,20 +275,21 @@ class CC_DLL PhysicsJointRatchet : public PhysicsJoint { public: static PhysicsJointRatchet* construct(PhysicsBody* a, PhysicsBody* b, float phase, float ratchet); - + float getAngle() const; void setAngle(float angle); float getPhase() const; void setPhase(float phase); float getRatchet() const; void setRatchet(float ratchet); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, float phase, float ratchet); - + virtual bool createConstraints() override; + protected: PhysicsJointRatchet() {} virtual ~PhysicsJointRatchet() {} + + float _phase; + float _ratchet; }; /** Keeps the angular velocity ratio of a pair of bodies constant. */ @@ -276,18 +297,20 @@ class CC_DLL PhysicsJointGear : public PhysicsJoint { public: static PhysicsJointGear* construct(PhysicsBody* a, PhysicsBody* b, float phase, float ratio); - + float getPhase() const; void setPhase(float phase); float getRatio() const; void setRatio(float ratchet); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, float phase, float ratio); - + + virtual bool createConstraints() override; + protected: PhysicsJointGear() {} virtual ~PhysicsJointGear() {} + + float _phase; + float _ratio; }; /** Keeps the relative angular velocity of a pair of bodies constant */ @@ -295,16 +318,16 @@ class CC_DLL PhysicsJointMotor : public PhysicsJoint { public: static PhysicsJointMotor* construct(PhysicsBody* a, PhysicsBody* b, float rate); - + float getRate() const; void setRate(float rate); - -protected: - bool init(PhysicsBody* a, PhysicsBody* b, float rate); - + virtual bool createConstraints() override; + protected: PhysicsJointMotor() {} virtual ~PhysicsJointMotor() {} + + float _rate; }; NS_CC_END diff --git a/cocos/physics/CCPhysicsShape.cpp b/cocos/physics/CCPhysicsShape.cpp index db851cd299..c768a8d6b6 100644 --- a/cocos/physics/CCPhysicsShape.cpp +++ b/cocos/physics/CCPhysicsShape.cpp @@ -50,7 +50,6 @@ PhysicsShape::PhysicsShape() , _scaleY(1.0f) , _newScaleX(1.0f) , _newScaleY(1.0f) -, _dirty(false) , _tag(0) , _categoryBitmask(UINT_MAX) , _collisionBitmask(UINT_MAX) @@ -112,50 +111,25 @@ void PhysicsShape::setMaterial(const PhysicsMaterial& material) setFriction(material.friction); } -void PhysicsShape::setScale(float scale) -{ - setScaleX(scale); - setScaleY(scale); -} - void PhysicsShape::setScale(float scaleX, float scaleY) { - setScaleX(scaleX); - setScaleY(scaleY); + if (_scaleX != scaleX || _scaleY != scaleY) + { + if (_type == Type::CIRCLE && scaleX != scaleY) + { + CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScale with different x and y"); + return; + } + _newScaleX = scaleX; + _newScaleY = scaleY; + updateScale(); + } } -void PhysicsShape::setScaleX(float scaleX) +void PhysicsShape::updateScale() { - if (_scaleX == scaleX) - { - return; - } - - _newScaleX = scaleX; - _dirty = true; -} - -void PhysicsShape::setScaleY(float scaleY) -{ - if (_scaleY == scaleY) - { - return; - } - - _newScaleY = scaleY; - _dirty = true; -} - -void PhysicsShape::update(float delta) -{ - CC_UNUSED_PARAM(delta); - - if (_dirty) - { - _scaleX = _newScaleX; - _scaleY = _newScaleY; - _dirty = false; - } + _scaleX = _newScaleX; + _scaleY = _newScaleY; } void PhysicsShape::addShape(cpShape* shape) @@ -399,63 +373,18 @@ Vec2 PhysicsShapeCircle::getOffset() return PhysicsHelper::cpv2point(cpCircleShapeGetOffset(_cpShapes.front())); } -void PhysicsShapeCircle::setScale(float scale) +void PhysicsShapeCircle::updateScale() { - if (_scaleX == scale) - { - return; - } - - _newScaleX = _newScaleY = scale; - _dirty = true; -} + cpFloat factor = std::abs(PhysicsHelper::float2cpfloat(_newScaleX / _scaleX)); -void PhysicsShapeCircle::setScale(float scaleX, float scaleY) -{ - if (scaleX != scaleY) - { - CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScale with different x and y"); - } - - if (_scaleX == scaleX) - { - return; - } - - _newScaleX = _newScaleY = scaleX; - _dirty = true; -} + cpShape* shape = _cpShapes.front(); + cpVect v = cpCircleShapeGetOffset(shape); + v = cpvmult(v, PhysicsHelper::float2cpfloat(factor)); + ((cpCircleShape*)shape)->c = v; -void PhysicsShapeCircle::setScaleX(float scale) -{ - CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScaleX"); - - setScale(scale); -} + cpCircleShapeSetRadius(shape, cpCircleShapeGetRadius(shape) * factor); -void PhysicsShapeCircle::setScaleY(float scale) -{ - CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScaleY"); - - setScale(scale); -} - -void PhysicsShapeCircle::update(float delta) -{ - if (_dirty) - { - cpFloat factor = std::abs(PhysicsHelper::float2cpfloat( _newScaleX / _scaleX )); - - auto shape = _cpShapes.front(); - auto v = cpCircleShapeGetOffset(shape); - v = cpvmult(v, PhysicsHelper::float2cpfloat(factor)); - ((cpCircleShape*)shape)->c = v; - - cpCircleShapeSetRadius(shape, cpCircleShapeGetRadius(shape) * factor); - } - - PhysicsShape::update(delta); - + PhysicsShape::updateScale(); } // PhysicsShapeEdgeSegment @@ -515,24 +444,21 @@ Vec2 PhysicsShapeEdgeSegment::getCenter() return ( a + b ) / 2; } -void PhysicsShapeEdgeSegment::update(float delta) +void PhysicsShapeEdgeSegment::updateScale() { - if (_dirty) - { - auto factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); - auto factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); - - auto shape = _cpShapes.front(); - auto a = cpSegmentShapeGetA(shape); - a.x *= factorX; - a.y *= factorY; - auto b = cpSegmentShapeGetB(shape); - b.x *= factorX; - b.y *= factorY; - cpSegmentShapeSetEndpoints(shape, a, b); - } - - PhysicsShape::update(delta); + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + cpShape* shape = _cpShapes.front(); + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); + + PhysicsShape::updateScale(); } // PhysicsShapeBox @@ -682,45 +608,42 @@ Vec2 PhysicsShapePolygon::getCenter() return PhysicsHelper::cpv2point(cpCentroidForPoly(((cpPolyShape*)_cpShapes.front())->numVerts, ((cpPolyShape*)_cpShapes.front())->verts)); } -void PhysicsShapePolygon::update(float delta) +void PhysicsShapePolygon::updateScale() { - if (_dirty) - { - cpFloat factorX = PhysicsHelper::float2cpfloat( _newScaleX / _scaleX ); - cpFloat factorY = PhysicsHelper::float2cpfloat( _newScaleY / _scaleY ); - - auto shape = _cpShapes.front(); - int count = cpPolyShapeGetNumVerts(shape); - cpVect* vects = ((cpPolyShape*)shape)->verts; - cpSplittingPlane* planes = ((cpPolyShape*)shape)->planes; + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); - for (int i = 0; i < count ; ++i) + auto shape = _cpShapes.front(); + int count = cpPolyShapeGetNumVerts(shape); + cpVect* vects = ((cpPolyShape*)shape)->verts; + cpSplittingPlane* planes = ((cpPolyShape*)shape)->planes; + + for (int i = 0; i < count; ++i) + { + vects[i].x *= factorX; + vects[i].y *= factorY; + } + + // convert hole to clockwise + if (factorX * factorY < 0) + { + for (int i = 0; i < count / 2; ++i) { - vects[i].x *= factorX; - vects[i].y *= factorY; - } - - // convert hole to clockwise - if ( factorX * factorY < 0 ) - { - for (int i = 0; i < count / 2; ++i) - { - cpVect v = vects[i]; - vects[i] = vects[count - i - 1]; - vects[count - i - 1] = v; - } - } - - for (int i = 0; i < count; ++i) - { - cpVect n = cpvnormalize(cpvperp(cpvsub(vects[i], vects[(i + 1) % count]))); - - planes[i].n = n; - planes[i].d = cpvdot(n, vects[i]); + cpVect v = vects[i]; + vects[i] = vects[count - i - 1]; + vects[count - i - 1] = v; } } + + for (int i = 0; i < count; ++i) + { + cpVect n = cpvnormalize(cpvperp(cpvsub(vects[i], vects[(i + 1) % count]))); + + planes[i].n = n; + planes[i].d = cpvdot(n, vects[i]); + } - PhysicsShape::update(delta); + PhysicsShape::updateScale(); } // PhysicsShapeEdgeBox @@ -865,26 +788,23 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(const Vec2* points, int cou return nullptr; } -void PhysicsShapeEdgePolygon::update(float delta) +void PhysicsShapeEdgePolygon::updateScale() { - if (_dirty) + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + for (auto shape : _cpShapes) { - cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); - cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); - - for(auto shape : _cpShapes) - { - cpVect a = cpSegmentShapeGetA(shape); - a.x *= factorX; - a.y *= factorY; - cpVect b = cpSegmentShapeGetB(shape); - b.x *= factorX; - b.y *= factorY; - cpSegmentShapeSetEndpoints(shape, a, b); - } + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); } - PhysicsShape::update(delta); + PhysicsShape::updateScale(); } bool PhysicsShapeEdgeChain::init(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/) @@ -957,26 +877,23 @@ int PhysicsShapeEdgeChain::getPointsCount() const return static_cast(_cpShapes.size() + 1); } -void PhysicsShapeEdgeChain::update(float delta) +void PhysicsShapeEdgeChain::updateScale() { - if (_dirty) + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + for (auto shape : _cpShapes) { - cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); - cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); - - for(auto shape : _cpShapes) - { - cpVect a = cpSegmentShapeGetA(shape); - a.x *= factorX; - a.y *= factorY; - cpVect b = cpSegmentShapeGetB(shape); - b.x *= factorX; - b.y *= factorY; - cpSegmentShapeSetEndpoints(shape, a, b); - } + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); } - PhysicsShape::update(delta); + PhysicsShape::updateScale(); } void PhysicsShape::setGroup(int group) diff --git a/cocos/physics/CCPhysicsShape.h b/cocos/physics/CCPhysicsShape.h index 79fabf6f1f..9c456624ea 100644 --- a/cocos/physics/CCPhysicsShape.h +++ b/cocos/physics/CCPhysicsShape.h @@ -56,7 +56,7 @@ typedef struct CC_DLL PhysicsMaterial {} }PhysicsMaterial; -const PhysicsMaterial PHYSICSSHAPE_MATERIAL_DEFAULT(0.0f, 0.5f, 0.5f); +const PhysicsMaterial PHYSICSSHAPE_MATERIAL_DEFAULT; /** * @brief A shape for body. You do not create PhysicsWorld objects directly, instead, you can view PhysicsBody to see how to create it. @@ -153,11 +153,8 @@ protected: /** calculate the area of this shape */ virtual float calculateArea() { return 0.0f; } - virtual void setScale(float scale); virtual void setScale(float scaleX, float scaleY); - virtual void setScaleX(float scaleX); - virtual void setScaleY(float scaleY); - virtual void update(float delta); + virtual void updateScale(); void addShape(cpShape* shape); protected: @@ -176,7 +173,6 @@ protected: float _scaleY; float _newScaleX; float _newScaleY; - bool _dirty; PhysicsMaterial _material; int _tag; int _categoryBitmask; @@ -206,11 +202,7 @@ public: protected: bool init(float radius, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); virtual float calculateArea() override; - virtual void setScale(float scale) override; - virtual void setScale(float scaleX, float scaleY) override; - virtual void setScaleX(float scale) override; - virtual void setScaleY(float scale) override; - virtual void update(float delta) override; + virtual void updateScale() override; protected: PhysicsShapeCircle(); @@ -234,7 +226,7 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); float calculateArea() override; - virtual void update(float delta) override; + virtual void updateScale() override; protected: PhysicsShapePolygon(); @@ -270,7 +262,7 @@ public: protected: bool init(const Vec2& a, const Vec2& b, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); - virtual void update(float delta) override; + virtual void updateScale() override; protected: PhysicsShapeEdgeSegment(); @@ -290,7 +282,7 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); - virtual void update(float delta) override; + virtual void updateScale() override; protected: PhysicsShapeEdgePolygon(); @@ -327,7 +319,7 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); - virtual void update(float delta) override; + virtual void updateScale() override; protected: PhysicsShapeEdgeChain(); diff --git a/cocos/physics/CCPhysicsWorld.cpp b/cocos/physics/CCPhysicsWorld.cpp index 84b38e42db..4afeed85b8 100644 --- a/cocos/physics/CCPhysicsWorld.cpp +++ b/cocos/physics/CCPhysicsWorld.cpp @@ -481,7 +481,6 @@ void PhysicsWorld::doAddBody(PhysicsBody* body) } } - void PhysicsWorld::addBodyOrDelay(PhysicsBody* body) { auto removeBodyIter = _delayRemoveBodies.find(body); @@ -491,17 +490,10 @@ void PhysicsWorld::addBodyOrDelay(PhysicsBody* body) return; } - if (cpSpaceIsLocked(_cpSpace)) + if (_delayAddBodies.find(body) == _delayAddBodies.end()) { - if (_delayAddBodies.find(body) == _delayAddBodies.end()) - { - _delayAddBodies.pushBack(body); - _delayDirty = true; - } - } - else - { - doAddBody(body); + _delayAddBodies.pushBack(body); + _delayDirty = true; } } @@ -542,7 +534,6 @@ void PhysicsWorld::removeBody(int tag) void PhysicsWorld::removeBody(PhysicsBody* body) { - if (body->getWorld() != this) { CCLOG("Physics Warnning: this body doesn't belong to this world"); @@ -550,25 +541,11 @@ void PhysicsWorld::removeBody(PhysicsBody* body) } // destory the body's joints - for (auto joint : body->_joints) + auto removeCopy = body->_joints; + for (auto joint : removeCopy) { - // set destroy param to false to keep the iterator available - removeJoint(joint, false); - - PhysicsBody* other = (joint->getBodyA() == body ? joint->getBodyB() : joint->getBodyA()); - other->removeJoint(joint); - - // test the distraction is delaied or not - if (std::find(_delayRemoveJoints.rbegin(), _delayRemoveJoints.rend(), joint) != _delayRemoveJoints.rend()) - { - joint->_destoryMark = true; - } - else - { - delete joint; - } + removeJoint(joint, true); } - body->_joints.clear(); removeBodyOrDelay(body); @@ -598,54 +575,35 @@ void PhysicsWorld::removeBodyOrDelay(PhysicsBody* body) } } -void PhysicsWorld::doAddJoint(PhysicsJoint *joint) +void PhysicsWorld::removeJoint(PhysicsJoint* joint, bool destroy) { if (joint) { - for (auto constraint : joint->_cpConstraints) - { - cpSpaceAddConstraint(_cpSpace, constraint); - } - } -} - -void PhysicsWorld::removeJoint(PhysicsJoint* joint, bool destroy) -{ - if (joint->getWorld() != this) - { - if (destroy) + if (joint->getWorld() != this && destroy) { CCLOG("physics warnning: the joint is not in this world, it won't be destoried utill the body it conntect is destoried"); + return; } - return; - } - - removeJointOrDelay(joint); - - _joints.remove(joint); - joint->_world = nullptr; - - // clean the connection to this joint - if (destroy) - { - if (joint->getBodyA() != nullptr) + + joint->_destoryMark = destroy; + if (cpSpaceIsLocked(_cpSpace)) { - joint->getBodyA()->removeJoint(joint); - } - - if (joint->getBodyB() != nullptr) - { - joint->getBodyB()->removeJoint(joint); - } - - // test the distraction is delaied or not - if (std::find(_delayRemoveJoints.rbegin(), _delayRemoveJoints.rend(), joint) != _delayRemoveJoints.rend()) - { - joint->_destoryMark = true; + auto it = std::find(_delayAddJoints.begin(), _delayAddJoints.end(), joint); + if (it != _delayAddJoints.end()) + { + _delayAddJoints.erase(it); + return; + } + + if (std::find(_delayRemoveJoints.rbegin(), _delayRemoveJoints.rend(), joint) == _delayRemoveJoints.rend()) + { + _delayRemoveJoints.push_back(joint); + _delayDirty = true; + } } else { - delete joint; + doRemoveJoint(joint); } } } @@ -657,24 +615,25 @@ void PhysicsWorld::updateJoints() return; } - auto addCopy = _delayAddJoints; - _delayAddJoints.clear(); - for (auto joint : addCopy) + for (auto joint : _delayAddJoints) { - doAddJoint(joint); - } - - auto removeCopy = _delayRemoveJoints; - _delayRemoveJoints.clear(); - for (auto joint : removeCopy) - { - doRemoveJoint(joint); - - if (joint->_destoryMark) + joint->_world = this; + if (joint->initJoint()) + { + _joints.push_back(joint); + } + else { delete joint; } } + _delayAddJoints.clear(); + + for (auto joint : _delayRemoveJoints) + { + doRemoveJoint(joint); + } + _delayRemoveJoints.clear(); } void PhysicsWorld::removeShape(PhysicsShape* shape) @@ -691,95 +650,37 @@ void PhysicsWorld::removeShape(PhysicsShape* shape) } } -void PhysicsWorld::addJointOrDelay(PhysicsJoint* joint) +void PhysicsWorld::addJoint(PhysicsJoint* joint) { - auto it = std::find(_delayRemoveJoints.begin(), _delayRemoveJoints.end(), joint); - if (it != _delayRemoveJoints.end()) - { - _delayRemoveJoints.erase(it); - return; - } - - if (cpSpaceIsLocked(_cpSpace)) + if (joint) { + if (joint->getWorld() && joint->getWorld() != this) + { + joint->removeFormWorld(); + } + + auto it = std::find(_delayRemoveJoints.begin(), _delayRemoveJoints.end(), joint); + if (it != _delayRemoveJoints.end()) + { + _delayRemoveJoints.erase(it); + return; + } + if (std::find(_delayAddJoints.begin(), _delayAddJoints.end(), joint) == _delayAddJoints.end()) { _delayAddJoints.push_back(joint); _delayDirty = true; } - }else - { - doAddJoint(joint); } } -void PhysicsWorld::removeJointOrDelay(PhysicsJoint* joint) -{ - auto it = std::find(_delayAddJoints.begin(), _delayAddJoints.end(), joint); - if (it != _delayAddJoints.end()) - { - _delayAddJoints.erase(it); - return; - } - - if (cpSpaceIsLocked(_cpSpace)) - { - if (std::find(_delayRemoveJoints.rbegin(), _delayRemoveJoints.rend(), joint) == _delayRemoveJoints.rend()) - { - _delayRemoveJoints.push_back(joint); - _delayDirty = true; - } - }else - { - doRemoveJoint(joint); - } -} - -void PhysicsWorld::addJoint(PhysicsJoint* joint) -{ - if (joint->getWorld() != nullptr && joint->getWorld() != this) - { - joint->removeFormWorld(); - } - - addJointOrDelay(joint); - _joints.push_back(joint); - joint->_world = this; -} - void PhysicsWorld::removeAllJoints(bool destroy) { - for (auto joint : _joints) + auto removeCopy = _joints; + for (auto joint : removeCopy) { - removeJointOrDelay(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 (std::find(_delayRemoveJoints.rbegin(), _delayRemoveJoints.rend(), joint) != _delayRemoveJoints.rend()) - { - joint->_destoryMark = true; - } - else - { - delete joint; - } - } + removeJoint(joint, destroy); } - - _joints.clear(); } void PhysicsWorld::addShape(PhysicsShape* physicsShape) @@ -816,6 +717,23 @@ void PhysicsWorld::doRemoveJoint(PhysicsJoint* joint) { cpSpaceRemoveConstraint(_cpSpace, constraint); } + _joints.remove(joint); + joint->_world = nullptr; + + if (joint->getBodyA()) + { + joint->getBodyA()->removeJoint(joint); + } + + if (joint->getBodyB()) + { + joint->getBodyB()->removeJoint(joint); + } + + if (joint->_destoryMark) + { + delete joint; + } } void PhysicsWorld::removeAllBodies() @@ -889,11 +807,18 @@ void PhysicsWorld::step(float delta) void PhysicsWorld::update(float delta, bool userCall/* = false*/) { + if (delta < FLT_EPSILON) + { + return; + } + + _scene->updatePhysicsBodyTransform(_scene, _scene->getNodeToParentTransform(), 0, 1.0f, 1.0f); + while (_delayDirty) { - // the updateJoints must run before the updateBodies. - updateJoints(); updateBodies(); + updateJoints(); + _delayDirty = !(_delayAddBodies.size() == 0 && _delayRemoveBodies.size() == 0 && _delayAddJoints.size() == 0 && _delayRemoveJoints.size() == 0); } diff --git a/cocos/physics/CCPhysicsWorld.h b/cocos/physics/CCPhysicsWorld.h index 9612ba688c..f64852bf45 100644 --- a/cocos/physics/CCPhysicsWorld.h +++ b/cocos/physics/CCPhysicsWorld.h @@ -45,6 +45,7 @@ class PhysicsContact; typedef Vec2 Vect; +class Director; class Node; class Sprite; class Scene; @@ -188,12 +189,9 @@ protected: virtual void doAddBody(PhysicsBody* body); virtual void doRemoveBody(PhysicsBody* body); - virtual void doAddJoint(PhysicsJoint* joint); virtual void doRemoveJoint(PhysicsJoint* joint); virtual void addBodyOrDelay(PhysicsBody* body); virtual void removeBodyOrDelay(PhysicsBody* body); - virtual void addJointOrDelay(PhysicsJoint* joint); - virtual void removeJointOrDelay(PhysicsJoint* joint); virtual void updateBodies(); virtual void updateJoints(); @@ -228,6 +226,7 @@ protected: friend class Node; friend class Sprite; friend class Scene; + friend class Director; friend class PhysicsBody; friend class PhysicsShape; friend class PhysicsJoint; diff --git a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp index 9913e50e2b..93bcecb722 100644 --- a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp +++ b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp @@ -434,7 +434,6 @@ void PhysicsDemo::onTouchEnded(Touch* touch, Event* event) this->removeChild(it->second); _mouses.erase(it); } - } void PhysicsDemoLogoSmash::onEnter() @@ -716,8 +715,6 @@ void PhysicsDemoJoints::onEnter() listener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoJoints::onTouchEnded, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - //_scene->getPhysicsWorld()->setGravity(Point::ZERO); - float width = (VisibleRect::getVisibleRect().size.width - 10) / 4; float height = (VisibleRect::getVisibleRect().size.height - 50) / 4; @@ -734,7 +731,7 @@ void PhysicsDemoJoints::onEnter() { Vec2 offset(VisibleRect::leftBottom().x + 5 + j * width + width/2, VisibleRect::leftBottom().y + 50 + i * height + height/2); box->addShape(PhysicsShapeEdgeBox::create(Size(width, height), PHYSICSSHAPE_MATERIAL_DEFAULT, 1, offset)); - + switch (i*4 + j) { case 0: @@ -768,7 +765,6 @@ void PhysicsDemoJoints::onEnter() } case 2: { - auto sp1 = makeBall(offset - Vec2(30, 0), 10); sp1->getPhysicsBody()->setTag(DRAG_BODYS_TAG); auto sp2 = makeBox(offset + Vec2(30, 0), Size(30, 10)); @@ -988,6 +984,9 @@ void PhysicsDemoPump::onEnter() body->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(150, -80), VisibleRect::rightTop() + Vec2(-100, -150), staticMaterial, 2.0f)); body->setCategoryBitmask(0x01); + node->setPhysicsBody(body); + node->setPosition(Vec2::ZERO); + this->addChild(node); // balls for (int i = 0; i < 6; ++i) @@ -997,9 +996,8 @@ void PhysicsDemoPump::onEnter() addChild(ball); } - node->setPhysicsBody(body); - this->addChild(node); - + auto _world = _scene->getPhysicsWorld(); + Vec2 vec[4] = { VisibleRect::leftTop() + Vec2(102, -148), @@ -1008,30 +1006,6 @@ void PhysicsDemoPump::onEnter() VisibleRect::leftBottom() + Vec2(102, 20) }; - auto _world = _scene->getPhysicsWorld(); - - // small gear - auto sgear = Node::create(); - auto sgearB = PhysicsBody::createCircle(44); - sgear->setPhysicsBody(sgearB); - sgear->setPosition(VisibleRect::leftBottom() + Vec2(125, 0)); - this->addChild(sgear); - sgearB->setCategoryBitmask(0x04); - sgearB->setCollisionBitmask(0x04); - sgearB->setTag(1); - _world->addJoint(PhysicsJointPin::construct(body, sgearB, sgearB->getPosition())); - - - // big gear - auto bgear = Node::create(); - auto bgearB = PhysicsBody::createCircle(100); - bgear->setPhysicsBody(bgearB); - bgear->setPosition(VisibleRect::leftBottom() + Vec2(275, 0)); - this->addChild(bgear); - bgearB->setCategoryBitmask(0x04); - _world->addJoint(PhysicsJointPin::construct(body, bgearB, bgearB->getPosition())); - - // pump auto pump = Node::create(); auto center = PhysicsShape::getPolyonCenter(vec, 4); @@ -1041,8 +1015,31 @@ void PhysicsDemoPump::onEnter() this->addChild(pump); pumpB->setCategoryBitmask(0x02); pumpB->setGravityEnable(false); + + // small gear + auto sgear = Node::create(); + auto sgearB = PhysicsBody::createCircle(44); + sgear->setPhysicsBody(sgearB); + sgear->setPosition(VisibleRect::leftBottom() + Vec2(125, 0)); + this->addChild(sgear); + sgearB->setCategoryBitmask(0x04); + sgearB->setCollisionBitmask(0x04); + sgearB->setTag(1); + + _world->addJoint(PhysicsJointPin::construct(body, sgearB, sgear->getPosition())); _world->addJoint(PhysicsJointDistance::construct(pumpB, sgearB, Vec2(0, 0), Vec2(0, -44))); + // big gear + auto bgear = Node::create(); + auto bgearB = PhysicsBody::createCircle(100); + bgear->setPhysicsBody(bgearB); + bgear->setPosition(VisibleRect::leftBottom() + Vec2(275, 0)); + this->addChild(bgear); + bgearB->setCategoryBitmask(0x04); + + _world->addJoint(PhysicsJointPin::construct(bgearB, body, bgear->getPosition())); + _world->addJoint(PhysicsJointGear::construct(sgearB, bgearB, -M_PI_2, -2.0f)); + // plugger Vec2 seg[] = {VisibleRect::leftTop() + Vec2(75, -120), VisibleRect::leftBottom() + Vec2(75, -100)}; Vec2 segCenter = (seg[1] + seg[0])/2; @@ -1059,7 +1056,7 @@ void PhysicsDemoPump::onEnter() pluggerB->setCategoryBitmask(0x02); sgearB->setCollisionBitmask(0x04 | 0x01); _world->addJoint(PhysicsJointPin::construct(body, pluggerB, VisibleRect::leftBottom() + Vec2(75, -90))); - _world->addJoint(PhysicsJointDistance::construct(pluggerB, sgearB, pluggerB->world2Local(VisibleRect::leftBottom() + Vec2(75, 0)), Vec2(44, 0))); + _world->addJoint(PhysicsJointDistance::construct(pluggerB, sgearB, Vec2::ZERO, Vec2(44, 0))); } void PhysicsDemoPump::update(float delta)