diff --git a/cocos/physics/CCPhysicsBody.cpp b/cocos/physics/CCPhysicsBody.cpp index 8f1e9e5c1d..22a0010cbe 100644 --- a/cocos/physics/CCPhysicsBody.cpp +++ b/cocos/physics/CCPhysicsBody.cpp @@ -77,6 +77,9 @@ PhysicsBody::PhysicsBody() , _linearDamping(0.0f) , _angularDamping(0.0f) , _tag(0) +, _categoryBitmask(UINT_MAX) +, _collisionBitmask(UINT_MAX) +, _contactTestBitmask(0) { } @@ -109,11 +112,6 @@ PhysicsBody* PhysicsBody::create() return nullptr; } -void update(float delta) -{ - -} - PhysicsBody* PhysicsBody::createCircle(float radius, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); diff --git a/cocos/physics/CCPhysicsBody.h b/cocos/physics/CCPhysicsBody.h index 72cad042bc..65d9f7318a 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -276,8 +276,8 @@ protected: int _tag; int _categoryBitmask; - int _contactTestBitmask; int _collisionBitmask; + int _contactTestBitmask; friend class PhysicsWorld; friend class PhysicsShape; diff --git a/cocos/physics/CCPhysicsContact.h b/cocos/physics/CCPhysicsContact.h index 3f2ef8659c..9b9e3044c0 100644 --- a/cocos/physics/CCPhysicsContact.h +++ b/cocos/physics/CCPhysicsContact.h @@ -80,6 +80,7 @@ private: bool _notify; friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -94,7 +95,7 @@ private: static PhysicsContactPreSolve* create(); bool init(); - friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -109,7 +110,7 @@ private: static PhysicsContactPostSolve* create(); bool init(); - friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -125,20 +126,20 @@ public: /* * @brief it will called at two shapes start to contact, and only call it once. */ - std::function onContactBegin; + std::function onContactBegin; /* * @brief Two shapes are touching during this step. Return false from the callback to make world ignore the collision this step or true to process it normally. Additionally, you may override collision values, elasticity, or surface velocity values. */ - std::function onContactPreSolve; + std::function onContactPreSolve; /* * @brief Two shapes are touching and their collision response has been processed. You can retrieve the collision impulse or kinetic energy at this time if you want to use it to calculate sound volumes or damage amounts. See cpArbiter for more info */ - std::function onContactPostSolve; + std::function onContactPostSolve; /* * @brief it will called at two shapes separated, and only call it once. * onContactBegin and onContactEnd will called in pairs. */ - std::function onContactEnd; + std::function onContactEnd; }; NS_CC_END diff --git a/cocos/physics/CCPhysicsWorld.cpp b/cocos/physics/CCPhysicsWorld.cpp index 30939dc9fd..6ca256bc67 100644 --- a/cocos/physics/CCPhysicsWorld.cpp +++ b/cocos/physics/CCPhysicsWorld.cpp @@ -60,12 +60,45 @@ NS_CC_BEGIN #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +namespace +{ + typedef struct RayCastCallbackInfo + { + PhysicsWorld* world; + PhysicsRayCastCallback* callback; + Point p1; + Point p2; + void* data; + }RayCastCallbackInfo; + + typedef struct RectQueryCallbackInfo + { + PhysicsWorld* world; + PhysicsRectQueryCallback* callback; + void* data; + }RectQueryCallbackInfo; +} + +class PhysicsWorldCallback +{ +public: + static int collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, PhysicsWorld *world); + static int collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world); + static void collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world); + static void collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world); + static void rayCastCallbackFunc(cpShape *shape, cpFloat t, cpVect n, RayCastCallbackInfo *info); + static void rectQueryCallbackFunc(cpShape *shape, RectQueryCallbackInfo *info); + +private: + static bool continues; +}; + +bool PhysicsWorldCallback::continues = true; + const float PHYSICS_INFINITY = INFINITY; -int PhysicsWorld::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, void *data) +int PhysicsWorldCallback::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, PhysicsWorld *world) { - PhysicsWorld* world = static_cast(data); - CP_ARBITER_GET_SHAPES(arb, a, b); auto ita = PhysicsShapeInfo::map.find(a); @@ -78,23 +111,20 @@ int PhysicsWorld::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *spa return world->collisionBeginCallback(*static_cast(arb->data)); } -int PhysicsWorld::collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, void *data) +int PhysicsWorldCallback::collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) { - PhysicsWorld* world = static_cast(data); return world->collisionPreSolveCallback(*static_cast(arb->data), PhysicsContactPreSolve()); } -void PhysicsWorld::collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, void *data) +void PhysicsWorldCallback::collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) { - PhysicsWorld* world = static_cast(data); world->collisionPostSolveCallback(*static_cast(arb->data), PhysicsContactPostSolve()); } -void PhysicsWorld::collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, void *data) +void PhysicsWorldCallback::collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world) { - PhysicsWorld* world = static_cast(data); PhysicsContact* contact = static_cast(arb->data); world->collisionSeparateCallback(*contact); @@ -102,6 +132,40 @@ void PhysicsWorld::collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, delete contact; } +void PhysicsWorldCallback::rayCastCallbackFunc(cpShape *shape, cpFloat t, cpVect n, RayCastCallbackInfo *info) +{ + if (!PhysicsWorldCallback::continues) + { + return; + } + + auto it = PhysicsShapeInfo::map.find(shape); + CC_ASSERT(it != PhysicsShapeInfo::map.end()); + + PhysicsWorldCallback::continues = info->callback->report(*info->world, + *it->second->shape, + Point(info->p1.x+(info->p2.x-info->p1.x)*t, info->p1.y+(info->p2.y-info->p1.y)*t), + Point(n.x, n.y), + (float)t, + info->data); +} + +void PhysicsWorldCallback::rectQueryCallbackFunc(cpShape *shape, RectQueryCallbackInfo *info) +{ + auto it = PhysicsShapeInfo::map.find(shape); + + CC_ASSERT(it != PhysicsShapeInfo::map.end()); + + if (!PhysicsWorldCallback::continues) + { + return; + } + + PhysicsWorldCallback::continues = info->callback->report(*info->world, + *it->second->shape, + info->data); +} + bool PhysicsWorld::init() { _info = new PhysicsWorldInfo(); @@ -109,10 +173,10 @@ bool PhysicsWorld::init() cpSpaceSetGravity(_info->space, PhysicsHelper::point2cpv(_gravity)); cpSpaceSetDefaultCollisionHandler(_info->space, - PhysicsWorld::collisionBeginCallbackFunc, - PhysicsWorld::collisionPreSolveCallbackFunc, - PhysicsWorld::collisionPostSolveCallbackFunc, - PhysicsWorld::collisionSeparateCallbackFunc, + (cpCollisionBeginFunc)PhysicsWorldCallback::collisionBeginCallbackFunc, + (cpCollisionPreSolveFunc)PhysicsWorldCallback::collisionPreSolveCallbackFunc, + (cpCollisionPostSolveFunc)PhysicsWorldCallback::collisionPostSolveCallbackFunc, + (cpCollisionSeparateFunc)PhysicsWorldCallback::collisionSeparateCallbackFunc, this); return true; @@ -368,12 +432,14 @@ int PhysicsWorld::collisionBeginCallback(PhysicsContact& contact) PhysicsBody* bodyA = contact.getShapeA()->getBody(); PhysicsBody* bodyB = contact.getShapeB()->getBody(); - if ((bodyA->getCategoryBitmask() & bodyB->getContactTestBitmask()) == 0) + if ((bodyA->getCategoryBitmask() & bodyB->getContactTestBitmask()) == 0 + || (bodyB->getContactTestBitmask() & bodyA->getCategoryBitmask()) == 0) { contact.setNotify(false); } - if ((bodyA->getCategoryBitmask() & bodyB->getCollisionBitmask()) == 0) + if ((bodyA->getCategoryBitmask() & bodyB->getCollisionBitmask()) == 0 + || (bodyB->getCategoryBitmask() & bodyA->getCollisionBitmask()) == 0) { ret = false; } @@ -384,10 +450,10 @@ int PhysicsWorld::collisionBeginCallback(PhysicsContact& contact) // so if the mask test is false, the two bodies won't have collision. if (ret) { - ret = _listener->onContactBegin(contact); + ret = _listener->onContactBegin(*this, contact); }else { - _listener->onContactBegin(contact); + _listener->onContactBegin(*this, contact); } } @@ -403,7 +469,7 @@ int PhysicsWorld::collisionPreSolveCallback(PhysicsContact& contact, const Physi if (_listener && _listener->onContactPreSolve) { - return _listener->onContactPreSolve(contact, solve); + return _listener->onContactPreSolve(*this, contact, solve); } return true; @@ -418,7 +484,7 @@ void PhysicsWorld::collisionPostSolveCallback(PhysicsContact& contact, const Phy if (_listener && _listener->onContactPreSolve) { - _listener->onContactPostSolve(contact, solve); + _listener->onContactPostSolve(*this, contact, solve); } } @@ -431,7 +497,7 @@ void PhysicsWorld::collisionSeparateCallback(PhysicsContact& contact) if (_listener && _listener->onContactEnd) { - _listener->onContactEnd(contact); + _listener->onContactEnd(*this, contact); } } @@ -456,6 +522,36 @@ void PhysicsWorld::setGravity(Point gravity) cpSpaceSetGravity(_info->space, PhysicsHelper::point2cpv(gravity)); } + +void PhysicsWorld::rayCast(PhysicsRayCastCallback& callback, Point point1, Point point2, void* data) +{ + RayCastCallbackInfo info = {this, &callback, point1, point2, data}; + cpSpaceSegmentQuery(this->_info->space, + PhysicsHelper::point2cpv(point1), + PhysicsHelper::point2cpv(point2), + CP_ALL_LAYERS, + CP_NO_GROUP, + (cpSpaceSegmentQueryFunc)PhysicsWorldCallback::rayCastCallbackFunc, + &info); +} + + +void PhysicsWorld::rectQuery(PhysicsRectQueryCallback& callback, Rect rect, void* data) +{ + RectQueryCallbackInfo info = {this, &callback, data}; + cpSpaceBBQuery(this->_info->space, + PhysicsHelper::rect2cpbb(rect), + CP_ALL_LAYERS, + CP_NO_GROUP, + (cpSpaceBBQueryFunc)PhysicsWorldCallback::rectQueryCallbackFunc, + &info); +} + +Array* PhysicsWorld::getAllBody() const +{ + return _bodys; +} + #elif (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) #endif diff --git a/cocos/physics/CCPhysicsWorld.h b/cocos/physics/CCPhysicsWorld.h index 3247ab5221..fa6a509dfc 100644 --- a/cocos/physics/CCPhysicsWorld.h +++ b/cocos/physics/CCPhysicsWorld.h @@ -33,12 +33,6 @@ #include "CCObject.h" #include "CCGeometry.h" - -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) -typedef struct cpArbiter cpArbiter; -typedef struct cpSpace cpSpace; -#endif - NS_CC_BEGIN class PhysicsBody; @@ -55,6 +49,29 @@ class Sprite; class Scene; class DrawNode; +class PhysicsWorld; +class PhysicsRayCastCallback +{ +public: + /** + * @brief Called for each fixture found in the query. You control how the ray cast + * proceeds by returning a float: + * return true: continue + * return false: terminate the ray cast + * @param fixture the fixture hit by the ray + * @param point the point of initial intersection + * @param normal the normal vector at the point of intersection + * @return true to continue, false to terminate + */ + std::function report; +}; + +class PhysicsRectQueryCallback +{ +public: + std::function report; +}; + /** * @brief An PhysicsWorld object simulates collisions and other physical properties. You do not create PhysicsWorld objects directly; instead, you can get it from an Scene object. */ @@ -68,9 +85,8 @@ public: /** Remove all joints from the physics world.*/ void removeAllJoints(); - Array* getBodysAlongRay(Point start, Point end) const; - Array* getBodysAtPoint(Point point) const; - Array* getBodysInRect(Rect rect) const; + void rayCast(PhysicsRayCastCallback& callback, Point point1, Point point2, void* data); + void rectQuery(PhysicsRectQueryCallback& callback, Rect rect, void* data); Array* getAllBody() const; /** Register a listener to receive contact callbacks*/ @@ -111,13 +127,6 @@ protected: virtual void collisionPostSolveCallback(PhysicsContact& contact, const PhysicsContactPostSolve& solve); virtual void collisionSeparateCallback(PhysicsContact& contact); -#if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) - static int collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, void *data); - static int collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, void *data); - static void collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, void *data); - static void collisionSeparateCallbackFunc(cpArbiter *arb, cpSpace *space, void *data); -#endif - protected: Point _gravity; float _speed; @@ -140,6 +149,7 @@ protected: friend class Scene; friend class PhysicsBody; friend class PhysicsShape; + friend class PhysicsWorldCallback; }; NS_CC_END diff --git a/cocos/physics/chipmunk/CCPhysicsHelper.h b/cocos/physics/chipmunk/CCPhysicsHelper.h index 337bb1a1df..bf6f6d14db 100644 --- a/cocos/physics/chipmunk/CCPhysicsHelper.h +++ b/cocos/physics/chipmunk/CCPhysicsHelper.h @@ -43,6 +43,8 @@ public: static cpVect size2cpv(const Size& size) { return cpv(size.width, size.height); } static float cpfloat2float(cpFloat f) { return f; } static cpFloat float2cpfloat(float f) { return f; } + static cpBB rect2cpbb(const Rect& rect) { return cpBBNew(rect.origin.x, rect.origin.y, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height); } + static Rect cpbb2rect(const cpBB& bb) { return Rect(bb.l, bb.b, bb.r, bb.t); } static Point* cpvs2points(const cpVect* cpvs, Point* points, int count) {