issue #2771: implements rayCast and rectQuery

This commit is contained in:
boyu0 2013-10-21 23:16:21 +08:00
parent 8fbfff97d9
commit e99b80b304
6 changed files with 155 additions and 48 deletions

View File

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

View File

@ -276,8 +276,8 @@ protected:
int _tag;
int _categoryBitmask;
int _contactTestBitmask;
int _collisionBitmask;
int _contactTestBitmask;
friend class PhysicsWorld;
friend class PhysicsShape;

View File

@ -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<bool(const PhysicsContact& contact)> onContactBegin;
std::function<bool(PhysicsWorld& world, const PhysicsContact& contact)> 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<bool(const PhysicsContact& contact, const PhysicsContactPreSolve& solve)> onContactPreSolve;
std::function<bool(PhysicsWorld& world, const PhysicsContact& contact, const PhysicsContactPreSolve& solve)> 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<void(const PhysicsContact& contact, const PhysicsContactPostSolve& solve)> onContactPostSolve;
std::function<void(PhysicsWorld& world, const PhysicsContact& contact, const PhysicsContactPostSolve& solve)> onContactPostSolve;
/*
* @brief it will called at two shapes separated, and only call it once.
* onContactBegin and onContactEnd will called in pairs.
*/
std::function<void(const PhysicsContact& contact)> onContactEnd;
std::function<void(PhysicsWorld& world, const PhysicsContact& contact)> onContactEnd;
};
NS_CC_END

View File

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

View File

@ -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<bool(PhysicsWorld&, PhysicsShape&, Point point, Point normal, float fraction, void* data)> report;
};
class PhysicsRectQueryCallback
{
public:
std::function<bool(PhysicsWorld&, PhysicsShape&, void* data)> 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

View File

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