mirror of https://github.com/axmolengine/axmol.git
issue #2771: add ray cast test
This commit is contained in:
parent
e99b80b304
commit
24561860f0
|
@ -97,7 +97,7 @@ public:
|
|||
virtual Point getOffset() { return Point::ZERO; }
|
||||
virtual Point getCenter() { return getOffset(); }
|
||||
|
||||
static Point* recenterPoints(Point* points, int count, Point center);
|
||||
static Point* recenterPoints(Point* points, int count, Point center = Point::ZERO);
|
||||
static Point getPolyonCenter(Point* points, int count);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -89,7 +89,7 @@ public:
|
|||
static void rayCastCallbackFunc(cpShape *shape, cpFloat t, cpVect n, RayCastCallbackInfo *info);
|
||||
static void rectQueryCallbackFunc(cpShape *shape, RectQueryCallbackInfo *info);
|
||||
|
||||
private:
|
||||
public:
|
||||
static bool continues;
|
||||
};
|
||||
|
||||
|
@ -391,12 +391,16 @@ void PhysicsWorld::drawWithShape(DrawNode* node, PhysicsShape* shape)
|
|||
Point centre = PhysicsHelper::cpv2point(cpBodyGetPos(cpShapeGetBody(shape)))
|
||||
+ PhysicsHelper::cpv2point(cpCircleShapeGetOffset(shape));
|
||||
|
||||
Point seg[4] = {};
|
||||
seg[0] = Point(centre.x - radius, centre.y - radius);
|
||||
seg[1] = Point(centre.x - radius, centre.y + radius);
|
||||
seg[2] = Point(centre.x + radius, centre.y + radius);
|
||||
seg[3] = Point(centre.x + radius, centre.y - radius);
|
||||
node->drawPolygon(seg, 4, Color4F(), 1, Color4F(1, 0, 0, 1));
|
||||
static const int CIRCLE_SEG_NUM = 12;
|
||||
Point seg[CIRCLE_SEG_NUM] = {};
|
||||
|
||||
for (int i = 0; i < CIRCLE_SEG_NUM; ++i)
|
||||
{
|
||||
float angle = (float)i * M_PI / (float)CIRCLE_SEG_NUM * 2.0f;
|
||||
Point d(radius * cosf(angle), radius * sinf(angle));
|
||||
seg[i] = centre + d;
|
||||
}
|
||||
node->drawPolygon(seg, CIRCLE_SEG_NUM, Color4F(1.0f, 0.0f, 0.0f, 0.3f), 1, Color4F(1, 0, 0, 1));
|
||||
break;
|
||||
}
|
||||
case CP_SEGMENT_SHAPE:
|
||||
|
@ -525,26 +529,36 @@ void PhysicsWorld::setGravity(Point 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);
|
||||
if (callback.report != nullptr)
|
||||
{
|
||||
RayCastCallbackInfo info = {this, &callback, point1, point2, data};
|
||||
|
||||
PhysicsWorldCallback::continues = true;
|
||||
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);
|
||||
if (callback.report != nullptr)
|
||||
{
|
||||
RectQueryCallbackInfo info = {this, &callback, data};
|
||||
|
||||
PhysicsWorldCallback::continues = true;
|
||||
cpSpaceBBQuery(this->_info->space,
|
||||
PhysicsHelper::rect2cpbb(rect),
|
||||
CP_ALL_LAYERS,
|
||||
CP_NO_GROUP,
|
||||
(cpSpaceBBQueryFunc)PhysicsWorldCallback::rectQueryCallbackFunc,
|
||||
&info);
|
||||
}
|
||||
}
|
||||
|
||||
Array* PhysicsWorld::getAllBody() const
|
||||
|
|
|
@ -53,6 +53,10 @@ class PhysicsWorld;
|
|||
class PhysicsRayCastCallback
|
||||
{
|
||||
public:
|
||||
PhysicsRayCastCallback()
|
||||
: report(nullptr)
|
||||
{}
|
||||
virtual ~PhysicsRayCastCallback(){}
|
||||
/**
|
||||
* @brief Called for each fixture found in the query. You control how the ray cast
|
||||
* proceeds by returning a float:
|
||||
|
@ -63,13 +67,19 @@ public:
|
|||
* @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;
|
||||
std::function<bool(PhysicsWorld&, PhysicsShape&, Point, Point, float, void*)> report;
|
||||
};
|
||||
|
||||
class PhysicsRectQueryCallback
|
||||
{
|
||||
public:
|
||||
std::function<bool(PhysicsWorld&, PhysicsShape&, void* data)> report;
|
||||
PhysicsRectQueryCallback()
|
||||
: report(nullptr)
|
||||
{}
|
||||
virtual ~PhysicsRectQueryCallback(){}
|
||||
|
||||
public:
|
||||
std::function<bool(PhysicsWorld&, PhysicsShape&, void*)> report;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace
|
|||
CL(PhysicsDemoPyramidStack),
|
||||
CL(PhysicsDemoPlink),
|
||||
CL(PhysicsDemoClickAdd),
|
||||
CL(PhysicsDemoRayCast),
|
||||
};
|
||||
|
||||
static int sceneIdx=-1;
|
||||
|
@ -48,6 +49,8 @@ namespace
|
|||
|
||||
return layer;
|
||||
}
|
||||
|
||||
static const Color4F STATIC_COLOR = {1.0f, 0.0f, 0.0f, 1.0f};
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +90,8 @@ void PhysicsTestScene::toggleDebug()
|
|||
|
||||
PhysicsDemo::PhysicsDemo()
|
||||
: _scene(nullptr)
|
||||
, _ball(nullptr)
|
||||
, _spriteTexture(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -304,22 +309,62 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
Node* PhysicsDemoLogoSmash::makeBall(float x, float y)
|
||||
Sprite* PhysicsDemo::makeBall(float x, float y, float radius, PhysicsMaterial material)
|
||||
{
|
||||
auto ball = Sprite::createWithTexture(_ball->getTexture());
|
||||
ball->setScale(0.1);
|
||||
Sprite* ball = nullptr;
|
||||
if (_ball != nullptr)
|
||||
{
|
||||
ball = Sprite::createWithTexture(_ball->getTexture());
|
||||
}else
|
||||
{
|
||||
ball = Sprite::create("Images/ball.png");
|
||||
}
|
||||
|
||||
auto body = PhysicsBody::createCircle(0.95, PhysicsMaterial(1, 0, 0));
|
||||
body->setMass(1.0);
|
||||
body->setMoment(PHYSICS_INFINITY);
|
||||
ball->setScale(0.13f * radius);
|
||||
|
||||
auto body = PhysicsBody::createCircle(radius, material);
|
||||
ball->setPhysicsBody(body);
|
||||
|
||||
ball->setPosition(Point(x, y));
|
||||
|
||||
return ball;
|
||||
}
|
||||
|
||||
Sprite* PhysicsDemo::makeBox(float x, float y, Size size, PhysicsMaterial material)
|
||||
{
|
||||
auto box = CCRANDOM_0_1() > 0.5f ? Sprite::create("Images/YellowSquare.png") : Sprite::create("Images/CyanSquare.png");
|
||||
|
||||
box->setScaleX(size.width/100.0f);
|
||||
box->setScaleY(size.height/100.0f);
|
||||
|
||||
auto body = PhysicsBody::createBox(size);
|
||||
box->setPhysicsBody(body);
|
||||
box->setPosition(Point(x, y));
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
Sprite* PhysicsDemo::makeTriangle(float x, float y, Size size, PhysicsMaterial material)
|
||||
{
|
||||
auto triangle = CCRANDOM_0_1() > 0.5f ? Sprite::create("Images/YellowTriangle.png") : Sprite::create("Images/CyanTriangle.png");
|
||||
|
||||
if(size.height == 0)
|
||||
{
|
||||
triangle->setScale(size.width/100.0f);
|
||||
}else
|
||||
{
|
||||
triangle->setScaleX(size.width/50.0f);
|
||||
triangle->setScaleY(size.height/43.5f);
|
||||
}
|
||||
|
||||
Point vers[] = { Point(0, size.height/2), Point(size.width/2, -size.height/2), Point(-size.width/2, -size.height/2)};
|
||||
|
||||
auto body = PhysicsBody::createPolygon(vers, 3);
|
||||
triangle->setPhysicsBody(body);
|
||||
triangle->setPosition(Point(x, y));
|
||||
|
||||
return triangle;
|
||||
}
|
||||
|
||||
void PhysicsDemoLogoSmash::onEnter()
|
||||
{
|
||||
PhysicsDemo::onEnter();
|
||||
|
@ -337,19 +382,22 @@ void PhysicsDemoLogoSmash::onEnter()
|
|||
float x_jitter = 0.05*frand();
|
||||
float y_jitter = 0.05*frand();
|
||||
|
||||
_ball->addChild(makeBall(2*(x - logo_width/2 + x_jitter) + VisibleRect::getVisibleRect().size.width/2,
|
||||
2*(logo_height-y + y_jitter) + VisibleRect::getVisibleRect().size.height/2 - logo_height/2));
|
||||
Node* ball = makeBall(2*(x - logo_width/2 + x_jitter) + VisibleRect::getVisibleRect().size.width/2,
|
||||
2*(logo_height-y + y_jitter) + VisibleRect::getVisibleRect().size.height/2 - logo_height/2,
|
||||
0.95f, PhysicsMaterial(1.0f, 0.0f, 0.0f));
|
||||
|
||||
ball->getPhysicsBody()->setMass(1.0);
|
||||
ball->getPhysicsBody()->setMoment(PHYSICS_INFINITY);
|
||||
|
||||
_ball->addChild(ball);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto bullet = Sprite::createWithTexture(_ball->getTexture());
|
||||
bullet->setScale(0.5);
|
||||
|
||||
auto body = PhysicsBody::createCircle(8, PhysicsMaterial(PHYSICS_INFINITY, 0, 0));
|
||||
body->setVelocity(Point(400, 0));
|
||||
bullet->setPhysicsBody(body);
|
||||
auto bullet = makeBall(400, 0, 10, PhysicsMaterial(PHYSICS_INFINITY, 0, 0));
|
||||
bullet->getPhysicsBody()->setVelocity(Point(400, 0));
|
||||
|
||||
bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2));
|
||||
|
||||
|
@ -393,7 +441,7 @@ void PhysicsDemoPlink::onEnter()
|
|||
{
|
||||
PhysicsDemo::onEnter();
|
||||
|
||||
auto node = Node::create();
|
||||
auto node = DrawNode::create();
|
||||
auto body = PhysicsBody::create();
|
||||
body->setDynamic(false);
|
||||
node->setPhysicsBody(body);
|
||||
|
@ -405,7 +453,11 @@ void PhysicsDemoPlink::onEnter()
|
|||
{
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
body->addShape(PhysicsShapePolygon::create(tris, 3, PHYSICSSHAPE_MATERIAL_DEFAULT, Point(rect.origin.x + rect.size.width/9*i + (j%2)*40 - 20, rect.origin.y + j*70)));
|
||||
Point offset(rect.origin.x + rect.size.width/9*i + (j%2)*40 - 20, rect.origin.y + j*70);
|
||||
body->addShape(PhysicsShapePolygon::create(tris, 3, PHYSICSSHAPE_MATERIAL_DEFAULT, offset));
|
||||
|
||||
Point drawVec[] = {tris[0] + offset, tris[1] + offset, tris[2] + offset};
|
||||
node->drawPolygon(drawVec, 3, STATIC_COLOR, 1, STATIC_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,4 +468,209 @@ void PhysicsDemoPlink::onEnter()
|
|||
std::string PhysicsDemoPlink::title()
|
||||
{
|
||||
return "Plink";
|
||||
}
|
||||
|
||||
PhysicsDemoRayCast::PhysicsDemoRayCast()
|
||||
: _angle(0.0f)
|
||||
, _node(nullptr)
|
||||
, _mode(0)
|
||||
{}
|
||||
|
||||
void PhysicsDemoRayCast::onEnter()
|
||||
{
|
||||
PhysicsDemo::onEnter();
|
||||
setTouchEnabled(true);
|
||||
|
||||
_scene->getPhysicsWorld()->setGravity(Point::ZERO);
|
||||
|
||||
auto node = DrawNode::create();
|
||||
node->setPhysicsBody(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Point(0, 50), VisibleRect::rightBottom() + Point(0, 50)));
|
||||
node->drawSegment(VisibleRect::leftBottom() + Point(0, 50), VisibleRect::rightBottom() + Point(0, 50), 1, STATIC_COLOR);
|
||||
this->addChild(node);
|
||||
|
||||
MenuItemFont::setFontSize(18);
|
||||
auto item = MenuItemFont::create("Change Mode(any)", CC_CALLBACK_1(PhysicsDemoRayCast::changeModeCallback, this));
|
||||
|
||||
auto menu = Menu::create(item, NULL);
|
||||
this->addChild(menu);
|
||||
menu->setPosition(Point(VisibleRect::left().x+100, VisibleRect::top().y-10));
|
||||
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
void PhysicsDemoRayCast::changeModeCallback(Object* sender)
|
||||
{
|
||||
_mode = (_mode + 1) % 3;
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case 0:
|
||||
((MenuItemFont*)sender)->setString("Change Mode(any)");
|
||||
break;
|
||||
case 1:
|
||||
((MenuItemFont*)sender)->setString("Change Mode(nearest)");
|
||||
break;
|
||||
case 2:
|
||||
((MenuItemFont*)sender)->setString("Change Mode(multiple)");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PhysicsDemoRayCast::anyRay(PhysicsWorld& world, PhysicsShape& shape, Point point, Point normal, float fraction, void* data)
|
||||
{
|
||||
*((Point*)data) = point;
|
||||
return false;
|
||||
}
|
||||
|
||||
class PhysicsDemoNearestRayCastCallback : public PhysicsRayCastCallback
|
||||
{
|
||||
public:
|
||||
PhysicsDemoNearestRayCastCallback();
|
||||
|
||||
private:
|
||||
float _friction;
|
||||
};
|
||||
|
||||
PhysicsDemoNearestRayCastCallback::PhysicsDemoNearestRayCastCallback()
|
||||
: _friction(1.0f)
|
||||
{
|
||||
report = [this](PhysicsWorld& world, PhysicsShape& shape, Point point, Point normal, float fraction, void* data)->bool
|
||||
{
|
||||
if (_friction > fraction)
|
||||
{
|
||||
*((Point*)data) = point;
|
||||
_friction = fraction;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static const int MAX_MULTI_RAYCAST_NUM = 5;
|
||||
}
|
||||
|
||||
class PhysicsDemoMultiRayCastCallback : public PhysicsRayCastCallback
|
||||
{
|
||||
public:
|
||||
PhysicsDemoMultiRayCastCallback();
|
||||
|
||||
public:
|
||||
Point points[MAX_MULTI_RAYCAST_NUM];
|
||||
int num;
|
||||
};
|
||||
|
||||
PhysicsDemoMultiRayCastCallback::PhysicsDemoMultiRayCastCallback()
|
||||
: num(0)
|
||||
{
|
||||
report = [this](PhysicsWorld& world, PhysicsShape& shape, Point point, Point normal, float fraction, void* data)->bool
|
||||
{
|
||||
if (num < MAX_MULTI_RAYCAST_NUM)
|
||||
{
|
||||
points[num++] = point;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
void PhysicsDemoRayCast::update(float delta)
|
||||
{
|
||||
float L = 150.0f;
|
||||
Point point1 = VisibleRect::center();
|
||||
Point d(L * cosf(_angle), L * sinf(_angle));
|
||||
Point point2 = point1 + d;
|
||||
|
||||
removeChild(_node);
|
||||
_node = DrawNode::create();
|
||||
switch (_mode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
PhysicsRayCastCallback callback;
|
||||
Point point3 = point2;
|
||||
callback.report = anyRay;
|
||||
|
||||
_scene->getPhysicsWorld()->rayCast(callback, point1, point2, &point3);
|
||||
_node->drawSegment(point1, point3, 1, STATIC_COLOR);
|
||||
|
||||
if (point2 != point3)
|
||||
{
|
||||
_node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
addChild(_node);
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
PhysicsDemoNearestRayCastCallback callback;
|
||||
Point point3 = point2;
|
||||
|
||||
_scene->getPhysicsWorld()->rayCast(callback, point1, point2, &point3);
|
||||
_node->drawSegment(point1, point3, 1, STATIC_COLOR);
|
||||
|
||||
if (point2 != point3)
|
||||
{
|
||||
_node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
addChild(_node);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
PhysicsDemoMultiRayCastCallback callback;
|
||||
|
||||
_scene->getPhysicsWorld()->rayCast(callback, point1, point2, nullptr);
|
||||
|
||||
_node->drawSegment(point1, point2, 1, STATIC_COLOR);
|
||||
|
||||
for (int i = 0; i < callback.num; ++i)
|
||||
{
|
||||
_node->drawDot(callback.points[i], 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
addChild(_node);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_angle += 0.25f * M_PI / 180.0f;
|
||||
}
|
||||
|
||||
void PhysicsDemoRayCast::onTouchesEnded(const std::vector<Touch*>& touches, Event* event)
|
||||
{
|
||||
//Add a new body/atlas sprite at the touched location
|
||||
|
||||
for( auto &touch: touches)
|
||||
{
|
||||
auto location = touch->getLocation();
|
||||
|
||||
float r = CCRANDOM_0_1();
|
||||
|
||||
if (r < 1.0f/3.0f)
|
||||
{
|
||||
addChild(makeBall(location.x, location.y, 5 + CCRANDOM_0_1()*10));
|
||||
}else if(r < 2.0f/3.0f)
|
||||
{
|
||||
addChild(makeBox(location.x, location.y, Size(10 + CCRANDOM_0_1()*15, 10 + CCRANDOM_0_1()*15)));
|
||||
}else
|
||||
{
|
||||
addChild(makeTriangle(location.x, location.y, Size(10 + CCRANDOM_0_1()*20, 10 + CCRANDOM_0_1()*20)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string PhysicsDemoRayCast::title()
|
||||
{
|
||||
return "Ray Cast";
|
||||
}
|
|
@ -37,9 +37,13 @@ public:
|
|||
void toggleDebugCallback(Object* sender);
|
||||
|
||||
void addGrossiniAtPosition(Point p, float scale = 1.0);
|
||||
Sprite* makeBall(float x, float y, float radius, PhysicsMaterial material = {1.0f, 1.0f, 1.0f});
|
||||
Sprite* makeBox(float x, float y, Size size, PhysicsMaterial material = {1.0f, 1.0f, 1.0f});
|
||||
Sprite* makeTriangle(float x, float y, Size size, PhysicsMaterial material = {1.0f, 1.0f, 1.0f});
|
||||
|
||||
private:
|
||||
protected:
|
||||
Texture2D* _spriteTexture; // weak ref
|
||||
SpriteBatchNode* _ball;
|
||||
};
|
||||
|
||||
class PhysicsDemoClickAdd : public PhysicsDemo
|
||||
|
@ -57,11 +61,6 @@ class PhysicsDemoLogoSmash : public PhysicsDemo
|
|||
public:
|
||||
void onEnter() override;
|
||||
std::string title() override;
|
||||
|
||||
Node* makeBall(float x, float y);
|
||||
|
||||
private:
|
||||
SpriteBatchNode* _ball;
|
||||
};
|
||||
|
||||
class PhysicsDemoPyramidStack : public PhysicsDemo
|
||||
|
@ -78,4 +77,25 @@ public:
|
|||
std::string title() override;
|
||||
};
|
||||
|
||||
class PhysicsDemoRayCast : public PhysicsDemo
|
||||
{
|
||||
public:
|
||||
PhysicsDemoRayCast();
|
||||
public:
|
||||
void onEnter() override;
|
||||
std::string title() override;
|
||||
void update(float delta) override;
|
||||
|
||||
void onTouchesEnded(const std::vector<Touch*>& touches, Event* event) override;
|
||||
|
||||
void changeModeCallback(Object* sender);
|
||||
|
||||
static bool anyRay(PhysicsWorld& world, PhysicsShape& shape, Point point, Point normal, float fraction, void* data);
|
||||
|
||||
private:
|
||||
float _angle;
|
||||
DrawNode* _node;
|
||||
int _mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue