issue #2771: implement contact callbacks

This commit is contained in:
boyu0 2013-10-25 10:31:22 +08:00
parent a8ddca81bd
commit fdcf019665
8 changed files with 164 additions and 62 deletions

View File

@ -142,7 +142,7 @@ public:
/*
* @brief get all joints the body have
*/
inline const std::vector<PhysicsJoint*>* getJoints() const { return &_joints; }
inline const std::vector<PhysicsJoint*>& getJoints() const { return _joints; }
/*
* @brief get the sprite the body set to.

View File

@ -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()

View File

@ -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;
};
/*

View File

@ -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);
// }
}
}

View File

@ -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__

View File

@ -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;
}
}

View File

@ -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<PhysicsContact*>(arb->data));
return world->collisionBeginCallback(*contact);
}
int PhysicsWorldCallback::collisionPreSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world)
{
return world->collisionPreSolveCallback(*static_cast<PhysicsContact*>(arb->data),
PhysicsContactPreSolve());
return world->collisionPreSolveCallback(*static_cast<PhysicsContact*>(arb->data));
}
void PhysicsWorldCallback::collisionPostSolveCallbackFunc(cpArbiter *arb, cpSpace *space, PhysicsWorld *world)
{
world->collisionPostSolveCallback(*static_cast<PhysicsContact*>(arb->data),
PhysicsContactPostSolve());
world->collisionPostSolveCallback(*static_cast<PhysicsContact*>(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<PhysicsJoint*> 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);
}
}

View File

@ -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: