diff --git a/cocos/physics/CCPhysicsBody.cpp b/cocos/physics/CCPhysicsBody.cpp index 8f1e9e5c1d2b..22a0010cbefa 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 72cad042bc3a..65d9f7318aa0 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -276,8 +276,8 @@ class PhysicsBody : public Object//, public Clonable 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 3f2ef8659c02..9b9e3044c0a7 100644 --- a/cocos/physics/CCPhysicsContact.h +++ b/cocos/physics/CCPhysicsContact.h @@ -80,6 +80,7 @@ class PhysicsContact bool _notify; friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -94,7 +95,7 @@ class PhysicsContactPreSolve static PhysicsContactPreSolve* create(); bool init(); - friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -109,7 +110,7 @@ class PhysicsContactPostSolve static PhysicsContactPostSolve* create(); bool init(); - friend class PhysicsWorld; + friend class PhysicsWorldCallback; }; /* @@ -125,20 +126,20 @@ class PhysicsContactListener /* * @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/CCPhysicsJoint.cpp b/cocos/physics/CCPhysicsJoint.cpp index 18f63b710193..09b1de36dd22 100644 --- a/cocos/physics/CCPhysicsJoint.cpp +++ b/cocos/physics/CCPhysicsJoint.cpp @@ -103,15 +103,15 @@ void PhysicsJoint::setEnable(bool enable) } } -//PhysicsJointPin::PhysicsJointPin() -//{ -// -//} -// -//PhysicsJointPin::~PhysicsJointPin() -//{ -// -//} +PhysicsJointPin::PhysicsJointPin() +{ + +} + +PhysicsJointPin::~PhysicsJointPin() +{ + +} PhysicsJointFixed::PhysicsJointFixed() { diff --git a/cocos/physics/CCPhysicsShape.h b/cocos/physics/CCPhysicsShape.h index 4191c7e6b54c..ebbe646466f3 100644 --- a/cocos/physics/CCPhysicsShape.h +++ b/cocos/physics/CCPhysicsShape.h @@ -44,15 +44,11 @@ typedef struct PhysicsMaterial float restitution; float friction; - PhysicsMaterial() - : density(0.0f) - , restitution(0.0f) - , friction(0.0f){} - - PhysicsMaterial(float density, float restitution, float friction) - : density(density) - , restitution(restitution) - , friction(friction){} + static PhysicsMaterial make(float density, float restitution, float friction) + { + PhysicsMaterial var = {density, restitution, friction}; + return var; + } }PhysicsMaterial; const PhysicsMaterial PHYSICSSHAPE_MATERIAL_DEFAULT = {0.0f, 1.0f, 1.0f}; @@ -97,7 +93,7 @@ class PhysicsShape : public Object 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: diff --git a/cocos/physics/CCPhysicsWorld.cpp b/cocos/physics/CCPhysicsWorld.cpp index 30939dc9fde8..ec7514ef6da6 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) -const float PHYSICS_INFINITY = INFINITY; +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; +} -int PhysicsWorld::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, void *data) +class PhysicsWorldCallback { - PhysicsWorld* world = static_cast(data); +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); +public: + static bool continues; +}; + +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); 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; @@ -327,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: @@ -368,12 +436,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 +454,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 +473,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 +488,7 @@ void PhysicsWorld::collisionPostSolveCallback(PhysicsContact& contact, const Phy if (_listener && _listener->onContactPreSolve) { - _listener->onContactPostSolve(contact, solve); + _listener->onContactPostSolve(*this, contact, solve); } } @@ -431,7 +501,7 @@ void PhysicsWorld::collisionSeparateCallback(PhysicsContact& contact) if (_listener && _listener->onContactEnd) { - _listener->onContactEnd(contact); + _listener->onContactEnd(*this, contact); } } @@ -456,6 +526,51 @@ void PhysicsWorld::setGravity(Point gravity) cpSpaceSetGravity(_info->space, PhysicsHelper::point2cpv(gravity)); } + +void PhysicsWorld::rayCast(PhysicsRayCastCallback& callback, Point point1, Point point2, void* data) +{ + 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) +{ + 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* getShapesAtPoint(Point point) +{ + +} + +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 3247ab52217a..868889b539c1 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,39 @@ class Sprite; class Scene; class DrawNode; +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: + * 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: + PhysicsRectQueryCallback() + : report(nullptr) + {} + virtual ~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 +95,9 @@ class PhysicsWorld /** 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* getShapesAtPoint(Point point); Array* getAllBody() const; /** Register a listener to receive contact callbacks*/ @@ -111,13 +138,6 @@ class PhysicsWorld 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 +160,7 @@ class PhysicsWorld 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 337bb1a1dfb5..bf6f6d14dbd6 100644 --- a/cocos/physics/chipmunk/CCPhysicsHelper.h +++ b/cocos/physics/chipmunk/CCPhysicsHelper.h @@ -43,6 +43,8 @@ class PhysicsHelper 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) { diff --git a/cocos/physics/chipmunk/CCPhysicsJointInfo.cpp b/cocos/physics/chipmunk/CCPhysicsJointInfo.cpp index 7a44587ba56d..b3fc37671050 100644 --- a/cocos/physics/chipmunk/CCPhysicsJointInfo.cpp +++ b/cocos/physics/chipmunk/CCPhysicsJointInfo.cpp @@ -24,8 +24,11 @@ #include "CCPhysicsJointInfo.h" #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +#include NS_CC_BEGIN +std::map PhysicsJointInfo::map; + PhysicsJointInfo::PhysicsJointInfo(PhysicsJoint* joint) : joint(joint) { diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index 91c67da54d6c..907a0df83a5a 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -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::make(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::make(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,238 @@ 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& 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"; +} + + +void PhysicsDemoJoints::onEnter() +{ + PhysicsDemo::onEnter(); + + setTouchEnabled(true); + + _scene->getPhysicsWorld()->setGravity(Point::ZERO); + + +} + +void PhysicsDemoJoints::onTouchesEnded(const std::vector& touches, Event* event) +{ + //Add a new body/atlas sprite at the touched location + + for( auto &touch: touches) + { + auto location = touch->getLocation(); + + + } +} + +std::string PhysicsDemoJoints::title() +{ + return "Joints"; } \ No newline at end of file diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h index 34f8053b3721..9df12624de61 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h @@ -37,9 +37,13 @@ class PhysicsDemo : public BaseTest 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,32 @@ class PhysicsDemoPlink : public PhysicsDemo 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& 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; +}; + +class PhysicsDemoJoints : public PhysicsDemo +{ +public: + void onEnter() override; + std::string title() override; + void onTouchesEnded(const std::vector& touches, Event* event) override; +}; + #endif diff --git a/samples/Cpp/TestCpp/Resources/Images/CyanTriangle.png b/samples/Cpp/TestCpp/Resources/Images/CyanTriangle.png new file mode 100644 index 000000000000..b443ce9ba9ba Binary files /dev/null and b/samples/Cpp/TestCpp/Resources/Images/CyanTriangle.png differ diff --git a/samples/Cpp/TestCpp/Resources/Images/YellowTriangle.png b/samples/Cpp/TestCpp/Resources/Images/YellowTriangle.png new file mode 100644 index 000000000000..e6e03b352ecc Binary files /dev/null and b/samples/Cpp/TestCpp/Resources/Images/YellowTriangle.png differ