From fdcf0196659fd97de2d58643fbb77b937ab32204 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Fri, 25 Oct 2013 10:31:22 +0800 Subject: [PATCH] issue #2771: implement contact callbacks --- cocos/physics/CCPhysicsBody.h | 2 +- cocos/physics/CCPhysicsContact.cpp | 103 ++++++++++++++++++++--------- cocos/physics/CCPhysicsContact.h | 56 +++++++++++++--- cocos/physics/CCPhysicsJoint.cpp | 8 +-- cocos/physics/CCPhysicsSetting.h | 5 ++ cocos/physics/CCPhysicsShape.cpp | 4 +- cocos/physics/CCPhysicsWorld.cpp | 42 +++++++++--- cocos/physics/CCPhysicsWorld.h | 6 +- 8 files changed, 164 insertions(+), 62 deletions(-) diff --git a/cocos/physics/CCPhysicsBody.h b/cocos/physics/CCPhysicsBody.h index f1715b0f1a..ad3ea332fa 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -142,7 +142,7 @@ public: /* * @brief get all joints the body have */ - inline const std::vector* getJoints() const { return &_joints; } + inline const std::vector& getJoints() const { return _joints; } /* * @brief get the sprite the body set to. diff --git a/cocos/physics/CCPhysicsContact.cpp b/cocos/physics/CCPhysicsContact.cpp index 1ec9667d6f..71ed2beb01 100644 --- a/cocos/physics/CCPhysicsContact.cpp +++ b/cocos/physics/CCPhysicsContact.cpp @@ -32,6 +32,8 @@ #include "chipmunk/CCPhysicsContactInfo.h" #include "box2d/CCPhysicsContactInfo.h" +#include "chipmunk/CCPhysicsHelper.h" +#include "box2d/CCPhysicsHelper.h" NS_CC_BEGIN @@ -39,7 +41,11 @@ PhysicsContact::PhysicsContact() : _shapeA(nullptr) , _shapeB(nullptr) , _info(nullptr) +, _notify(true) +, _begin(false) , _data(nullptr) +, _contactInfo(nullptr) +, _contactData(nullptr) { } @@ -47,6 +53,7 @@ PhysicsContact::PhysicsContact() PhysicsContact::~PhysicsContact() { CC_SAFE_DELETE(_info); + CC_SAFE_DELETE(_contactData); } PhysicsContact* PhysicsContact::create(PhysicsShape* a, PhysicsShape* b) @@ -78,37 +85,69 @@ bool PhysicsContact::init(PhysicsShape* a, PhysicsShape* b) return false; } -// PhysicsContactPreSolve implementation -PhysicsContactPreSolve::PhysicsContactPreSolve() +void PhysicsContact::generateContactData() { + if (_contactInfo == nullptr) + { + return; + } + cpArbiter* arb = (cpArbiter*)_contactInfo; + _contactData = new PhysicsContactData(); + _contactData->count = cpArbiterGetCount(arb); + for (int i=0; i<_contactData->count; ++i) + { + _contactData->points[i] = PhysicsHelper::cpv2point(cpArbiterGetPoint(arb, i)); + } + + _contactData->normal = _contactData->count > 0 ? PhysicsHelper::cpv2point(cpArbiterGetNormal(arb, 0)) : Point::ZERO; +} + +// PhysicsContactPreSolve implementation +PhysicsContactPreSolve::PhysicsContactPreSolve(PhysicsContactData* data, void* contactInfo) +: _preContactData(data) +, _contactInfo(contactInfo) +{ +} + +float PhysicsContactPreSolve::getElasticity() +{ + return ((cpArbiter*)_contactInfo)->e; +} + +float PhysicsContactPreSolve::getFriciton() +{ + return ((cpArbiter*)_contactInfo)->u; +} + +Point PhysicsContactPreSolve::getSurfaceVelocity() +{ + return PhysicsHelper::cpv2point(((cpArbiter*)_contactInfo)->surface_vr); +} + +void PhysicsContactPreSolve::setElasticity(float elasticity) +{ + ((cpArbiter*)_contactInfo)->e = elasticity; +} + +void PhysicsContactPreSolve::setFriction(float friction) +{ + ((cpArbiter*)_contactInfo)->u = friction; +} + +void PhysicsContactPreSolve::setSurfaceVelocity(Point surfaceVelocity) +{ + ((cpArbiter*)_contactInfo)->surface_vr = PhysicsHelper::point2cpv(surfaceVelocity); } PhysicsContactPreSolve::~PhysicsContactPreSolve() { - + CC_SAFE_DELETE(_preContactData); } -PhysicsContactPreSolve* PhysicsContactPreSolve::create() -{ - PhysicsContactPreSolve * solve = new PhysicsContactPreSolve(); - if(solve && solve->init()) - { - return solve; - } - - CC_SAFE_DELETE(solve); - return nullptr; -} - -bool PhysicsContactPreSolve::init() -{ - return true; -} - - // PhysicsContactPostSolve implementation -PhysicsContactPostSolve::PhysicsContactPostSolve() +PhysicsContactPostSolve::PhysicsContactPostSolve(void* contactInfo) +: _contactInfo(contactInfo) { } @@ -118,21 +157,19 @@ PhysicsContactPostSolve::~PhysicsContactPostSolve() } -PhysicsContactPostSolve* PhysicsContactPostSolve::create() +float PhysicsContactPostSolve::getElasticity() { - PhysicsContactPostSolve * solve = new PhysicsContactPostSolve(); - if(solve && solve->init()) - { - return solve; - } - - CC_SAFE_DELETE(solve); - return nullptr; + return ((cpArbiter*)_contactInfo)->e; } -bool PhysicsContactPostSolve::init() +float PhysicsContactPostSolve::getFriciton() { - return true; + return ((cpArbiter*)_contactInfo)->u; +} + +Point PhysicsContactPostSolve::getSurfaceVelocity() +{ + return PhysicsHelper::cpv2point(((cpArbiter*)_contactInfo)->surface_vr); } PhysicsContactListener::PhysicsContactListener() diff --git a/cocos/physics/CCPhysicsContact.h b/cocos/physics/CCPhysicsContact.h index 9b9e3044c0..6c96539c92 100644 --- a/cocos/physics/CCPhysicsContact.h +++ b/cocos/physics/CCPhysicsContact.h @@ -38,6 +38,18 @@ class PhysicsWorld; class PhysicsContactInfo; + +typedef struct PhysicsContactData +{ + Point points[PHYSICS_CONTACT_POINT_MAX]; + int count; + Point normal; + + PhysicsContactData() + : count(0) + {} +}PhysicsContactData; + /** * @brief Contact infomation. it will created automatically when two shape contact with each other. and it will destoried automatically when two shape separated. */ @@ -52,6 +64,7 @@ public: * @brief get contact shape B. */ inline PhysicsShape* getShapeB() const { return _shapeB; } + inline const PhysicsContactData* getContactData() const { return _contactData; } /* * @brief get data. */ @@ -68,6 +81,8 @@ private: inline bool getNotify() { return _notify; } inline void setNotify(bool notify) { _notify = notify; } + void generateContactData(); + private: PhysicsContact(); ~PhysicsContact(); @@ -76,8 +91,12 @@ private: PhysicsShape* _shapeA; PhysicsShape* _shapeB; PhysicsContactInfo* _info; - void* _data; bool _notify; + bool _begin; + + void* _data; + void* _contactInfo; + PhysicsContactData* _contactData; friend class PhysicsWorld; friend class PhysicsWorldCallback; @@ -88,14 +107,27 @@ private: */ class PhysicsContactPreSolve { +public: + // getter/setter + float getElasticity(); + float getFriciton(); + Point getSurfaceVelocity(); + void setElasticity(float elasticity); + void setFriction(float friction); + void setSurfaceVelocity(Point surfaceVelocity); + private: - PhysicsContactPreSolve(); + PhysicsContactPreSolve(PhysicsContactData* data, void* contactInfo); ~PhysicsContactPreSolve(); - static PhysicsContactPreSolve* create(); - bool init(); +private: + float _elasticity; + float _friction; + Point _surfaceVelocity; + PhysicsContactData* _preContactData; + void* _contactInfo; - friend class PhysicsWorldCallback; + friend class PhysicsWorld; }; /* @@ -103,14 +135,20 @@ private: */ class PhysicsContactPostSolve { +public: + // getter + float getElasticity(); + float getFriciton(); + Point getSurfaceVelocity(); + private: - PhysicsContactPostSolve(); + PhysicsContactPostSolve(void* contactInfo); ~PhysicsContactPostSolve(); - static PhysicsContactPostSolve* create(); - bool init(); +private: + void* _contactInfo; - friend class PhysicsWorldCallback; + friend class PhysicsWorld; }; /* diff --git a/cocos/physics/CCPhysicsJoint.cpp b/cocos/physics/CCPhysicsJoint.cpp index 6cca90dd5b..5e475bf367 100644 --- a/cocos/physics/CCPhysicsJoint.cpp +++ b/cocos/physics/CCPhysicsJoint.cpp @@ -161,10 +161,10 @@ void PhysicsJoint::setCollisionEnable(bool enable) { _collisionEnable = enable; - for (auto shape : _bodyB->_shapes) - { - shape->_info->setGroup(enable ? _bodyB->_info->group : _bodyA->_info->group); - } +// for (auto shape : _bodyB->_shapes) +// { +// shape->_info->setGroup(enable ? _bodyB->_info->group : _bodyA->_info->group); +// } } } diff --git a/cocos/physics/CCPhysicsSetting.h b/cocos/physics/CCPhysicsSetting.h index b29b12054d..ee3214bcd7 100644 --- a/cocos/physics/CCPhysicsSetting.h +++ b/cocos/physics/CCPhysicsSetting.h @@ -46,6 +46,11 @@ namespace cocos2d { extern const float PHYSICS_INFINITY; + +#if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) + static const int PHYSICS_CONTACT_POINT_MAX = 4; +#else +#endif } #endif // __CCPHYSICS_SETTING_H__ diff --git a/cocos/physics/CCPhysicsShape.cpp b/cocos/physics/CCPhysicsShape.cpp index 6ffd7d86aa..77634e9113 100644 --- a/cocos/physics/CCPhysicsShape.cpp +++ b/cocos/physics/CCPhysicsShape.cpp @@ -272,12 +272,12 @@ void PhysicsShape::setBody(PhysicsBody *body) if (body == nullptr) { _info->setBody(nullptr); - _info->setGroup(CP_NO_GROUP); + //_info->setGroup(CP_NO_GROUP); _body = nullptr; }else { _info->setBody(body->_info->body); - _info->setGroup(body->_info->group); + //_info->setGroup(body->_info->group); _body = body; } } diff --git a/cocos/physics/CCPhysicsWorld.cpp b/cocos/physics/CCPhysicsWorld.cpp index 9085805e1d..451c7b82a2 100644 --- a/cocos/physics/CCPhysicsWorld.cpp +++ b/cocos/physics/CCPhysicsWorld.cpp @@ -60,6 +60,8 @@ NS_CC_BEGIN #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +const float PHYSICS_INFINITY = INFINITY; + namespace { typedef struct RayCastCallbackInfo @@ -96,8 +98,6 @@ public: bool PhysicsWorldCallback::continues = true; -const float PHYSICS_INFINITY = INFINITY; - int PhysicsWorldCallback::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, PhysicsWorld *world) { CP_ARBITER_GET_SHAPES(arb, a, b); @@ -108,20 +108,19 @@ int PhysicsWorldCallback::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSp PhysicsContact* contact = PhysicsContact::create(ita->second->shape, itb->second->shape); arb->data = contact; + contact->_contactInfo = arb; - return world->collisionBeginCallback(*static_cast(arb->data)); + return world->collisionBeginCallback(*contact); } int PhysicsWorldCallback::collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) { - return world->collisionPreSolveCallback(*static_cast(arb->data), - PhysicsContactPreSolve()); + return world->collisionPreSolveCallback(*static_cast(arb->data)); } void PhysicsWorldCallback::collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) { - world->collisionPostSolveCallback(*static_cast(arb->data), - PhysicsContactPostSolve()); + world->collisionPostSolveCallback(*static_cast(arb->data)); } void PhysicsWorldCallback::collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) @@ -445,7 +444,24 @@ int PhysicsWorld::collisionBeginCallback(PhysicsContact& contact) bool ret = true; PhysicsBody* bodyA = contact.getShapeA()->getBody(); PhysicsBody* bodyB = contact.getShapeB()->getBody(); + std::vector jointsA = bodyA->getJoints(); + // check the joint is collision enable or not + for (PhysicsJoint* joint : jointsA) + { + if (!joint->isCollisionEnable()) + { + PhysicsBody* body = joint->getBodyA() == bodyA ? bodyB : bodyA; + + if (body == bodyB) + { + contact.setNotify(false); + return false; + } + } + } + + // bitmask check if ((bodyA->getCategoryBitmask() & bodyB->getContactTestBitmask()) == 0 || (bodyB->getContactTestBitmask() & bodyA->getCategoryBitmask()) == 0) { @@ -460,6 +476,9 @@ int PhysicsWorld::collisionBeginCallback(PhysicsContact& contact) if (contact.getNotify() && _listener && _listener->onContactBegin) { + contact._begin = true; + contact.generateContactData(); + // the mask has high priority than _listener->onContactBegin. // so if the mask test is false, the two bodies won't have collision. if (ret) @@ -474,7 +493,7 @@ int PhysicsWorld::collisionBeginCallback(PhysicsContact& contact) return ret; } -int PhysicsWorld::collisionPreSolveCallback(PhysicsContact& contact, const PhysicsContactPreSolve& solve) +int PhysicsWorld::collisionPreSolveCallback(PhysicsContact& contact) { if (!contact.getNotify()) { @@ -483,13 +502,17 @@ int PhysicsWorld::collisionPreSolveCallback(PhysicsContact& contact, const Physi if (_listener && _listener->onContactPreSolve) { + PhysicsContactPreSolve solve(contact._begin ? nullptr : contact._contactData, contact._contactInfo); + contact._begin = false; + contact.generateContactData(); + return _listener->onContactPreSolve(*this, contact, solve); } return true; } -void PhysicsWorld::collisionPostSolveCallback(PhysicsContact& contact, const PhysicsContactPostSolve& solve) +void PhysicsWorld::collisionPostSolveCallback(PhysicsContact& contact) { if (!contact.getNotify()) { @@ -498,6 +521,7 @@ void PhysicsWorld::collisionPostSolveCallback(PhysicsContact& contact, const Phy if (_listener && _listener->onContactPreSolve) { + PhysicsContactPostSolve solve(contact._contactInfo); _listener->onContactPostSolve(*this, contact, solve); } } diff --git a/cocos/physics/CCPhysicsWorld.h b/cocos/physics/CCPhysicsWorld.h index 63c841cc93..34528d6270 100644 --- a/cocos/physics/CCPhysicsWorld.h +++ b/cocos/physics/CCPhysicsWorld.h @@ -40,8 +40,6 @@ class PhysicsJoint; class PhysicsWorldInfo; class PhysicsShape; class PhysicsContact; -class PhysicsContactPreSolve; -class PhysicsContactPostSolve; class PhysicsContactListener; class Array; @@ -135,8 +133,8 @@ protected: virtual int collisionBeginCallback(PhysicsContact& contact); - virtual int collisionPreSolveCallback(PhysicsContact& contact, const PhysicsContactPreSolve& solve); - virtual void collisionPostSolveCallback(PhysicsContact& contact, const PhysicsContactPostSolve& solve); + virtual int collisionPreSolveCallback(PhysicsContact& contact); + virtual void collisionPostSolveCallback(PhysicsContact& contact); virtual void collisionSeparateCallback(PhysicsContact& contact); protected: