diff --git a/cocos2dx/base_nodes/CCNode.cpp b/cocos2dx/base_nodes/CCNode.cpp index 8169029ebd..4db892fdd6 100644 --- a/cocos2dx/base_nodes/CCNode.cpp +++ b/cocos2dx/base_nodes/CCNode.cpp @@ -44,6 +44,10 @@ THE SOFTWARE. #include "event_dispatcher/CCEvent.h" #include "event_dispatcher/CCEventTouch.h" +#ifdef CC_USE_PHYSICS +#include "physics/CCPhysicsBody.h" +#endif + // externals #include "kazmath/GL/matrix.h" #include "support/component/CCComponent.h" @@ -128,6 +132,11 @@ Node::Node(void) , _componentContainer(NULL) , _eventPriority(0) , _oldEventPriority(0) +#ifdef CC_USE_PHYSICS +, _physicsBody(nullptr) +, _physicsPositionMark(true) +, _physicsRotationMark(true) +#endif { // set default scheduler and actionManager Director *director = Director::getInstance(); @@ -179,6 +188,10 @@ Node::~Node() CC_SAFE_DELETE(_componentContainer); removeAllEventListeners(); + +#ifdef CC_USE_PHYSICS + CC_SAFE_RELEASE(_physicsBody); +#endif } bool Node::init() @@ -257,6 +270,15 @@ void Node::setRotation(float newRotation) { _rotationX = _rotationY = newRotation; _transformDirty = _inverseDirty = true; + +#ifdef CC_USE_PHYSICS + if (_physicsBody && _physicsRotationMark) + { + _physicsBody->setRotation(newRotation); + } + + _physicsRotationMark = true; +#endif } float Node::getRotationX() const @@ -340,6 +362,15 @@ void Node::setPosition(const Point& newPosition) { _position = newPosition; _transformDirty = _inverseDirty = true; + +#ifdef CC_USE_PHYSICS + if (_physicsBody && _physicsPositionMark) + { + _physicsBody->setPosition(newPosition); + } + + _physicsPositionMark = true; +#endif } void Node::getPosition(float* x, float* y) const @@ -808,6 +839,7 @@ void Node::visit() { return; } + kmGLPushMatrix(); if (_grid && _grid->isActive()) @@ -1268,6 +1300,16 @@ Point Node::convertTouchToNodeSpaceAR(Touch *touch) const void Node::updateTransform() { +#ifdef CC_USE_PHYSICS + if (_physicsBody) + { + _physicsPositionMark = false; + _physicsRotationMark = false; + setPosition(_physicsBody->getPosition()); + setRotation(_physicsBody->getRotation()); + } +#endif + // Recursively iterate over children arrayMakeObjectsPerformSelector(_children, updateTransform, Node*); } @@ -1337,6 +1379,26 @@ void Node::setDirtyForAllEventListeners() } } +#ifdef CC_USE_PHYSICS +void Node::setPhysicsBody(PhysicsBody* body) +{ + if (_physicsBody != nullptr) + { + _physicsBody->release(); + } + + _physicsBody = body; + _physicsBody->retain(); + _physicsBody->setPosition(getPosition()); + _physicsBody->setRotation(getRotation()); +} + +PhysicsBody* Node::getPhysicsBody() const +{ + return _physicsBody; +} +#endif //CC_USE_PHYSICS + // NodeRGBA NodeRGBA::NodeRGBA() : _displayedOpacity(255) diff --git a/cocos2dx/base_nodes/CCNode.h b/cocos2dx/base_nodes/CCNode.h index b84786126d..605b178bbf 100644 --- a/cocos2dx/base_nodes/CCNode.h +++ b/cocos2dx/base_nodes/CCNode.h @@ -38,6 +38,7 @@ #include "script_support/CCScriptSupport.h" #include "CCProtocols.h" #include "event_dispatcher/CCEventDispatcher.h" +#include "physics/CCPhysicsSetting.h" #include @@ -56,6 +57,9 @@ class Component; class Dictionary; class ComponentContainer; class EventDispatcher; +#ifdef CC_USE_PHYSICS +class PhysicsBody; +#endif /** * @addtogroup base_nodes @@ -1374,6 +1378,19 @@ public: */ virtual void removeAllComponents(); /// @} end of component functions + + +#ifdef CC_USE_PHYSICS + /** + * set the PhysicsBody that let the sprite effect with physics + */ + virtual void setPhysicsBody(PhysicsBody* body); + + /** + * get the PhysicsBody the sprite have + */ + PhysicsBody* getPhysicsBody() const; +#endif private: @@ -1486,6 +1503,12 @@ protected: int _eventPriority; ///< The scene graph based priority of event listener. int _oldEventPriority; ///< The old scene graph based priority of event listener. static int _globalEventPriorityIndex; ///< The index of global event priority. + +#ifdef CC_USE_PHYSICS + PhysicsBody* _physicsBody; ///< the physicsBody the node have + bool _physicsPositionMark; ///< set this mark to false will skip the setRotation to physicsBody one time + bool _physicsRotationMark; ///< set this mark to false will skip the setPosition to physicsBody one time +#endif }; //#pragma mark - NodeRGBA diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp index 36f2947dc6..c48f95c860 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp +++ b/cocos2dx/layers_scenes_transitions_nodes/CCScene.cpp @@ -28,12 +28,13 @@ THE SOFTWARE. #include "CCDirector.h" #include "CCLayer.h" #include "sprite_nodes/CCSprite.h" +#include "sprite_nodes/CCSpriteBatchNode.h" #include "physics/CCPhysicsWorld.h" NS_CC_BEGIN Scene::Scene() -#ifdef _physicsWorld +#ifdef CC_USE_PHYSICS : _physicsWorld(nullptr) #endif { @@ -43,6 +44,9 @@ Scene::Scene() Scene::~Scene() { +#ifdef CC_USE_PHYSICS + CC_SAFE_DELETE(_physicsWorld); +#endif } bool Scene::init() @@ -129,15 +133,23 @@ void Scene::addChildToPhysicsWorld(Node* child) { if (_physicsWorld) { - auto addToPhysicsWorldFunc = [this](Object* node) -> void + std::function addToPhysicsWorldFunc = nullptr; + addToPhysicsWorldFunc = [this, &addToPhysicsWorldFunc](Object* child) -> void { - if (dynamic_cast(node) != nullptr) + if (dynamic_cast(child) != nullptr) { - Sprite* sp = dynamic_cast(node); - - if (sp->getPhysicsBody()) + Object* subChild = nullptr; + CCARRAY_FOREACH((dynamic_cast(child))->getChildren(), subChild) { - _physicsWorld->addChild(sp->getPhysicsBody()); + addToPhysicsWorldFunc(subChild); + } + }else if (dynamic_cast(child) != nullptr) + { + Node* node = dynamic_cast(child); + + if (node->getPhysicsBody()) + { + _physicsWorld->addBody(node->getPhysicsBody()); } } }; diff --git a/cocos2dx/layers_scenes_transitions_nodes/CCScene.h b/cocos2dx/layers_scenes_transitions_nodes/CCScene.h index a778af220a..c2e2aa7bcb 100644 --- a/cocos2dx/layers_scenes_transitions_nodes/CCScene.h +++ b/cocos2dx/layers_scenes_transitions_nodes/CCScene.h @@ -88,6 +88,7 @@ protected: #endif // CC_USE_PHYSICS friend class Layer; + friend class SpriteBatchNode; }; // end of scene group diff --git a/cocos2dx/physics/CCPhysicsBody.cpp b/cocos2dx/physics/CCPhysicsBody.cpp index 3fb5d485b1..2dc38bf286 100644 --- a/cocos2dx/physics/CCPhysicsBody.cpp +++ b/cocos2dx/physics/CCPhysicsBody.cpp @@ -42,6 +42,8 @@ #include "Box2D/CCPhysicsJointInfo.h" #include "chipmunk/CCPhysicsWorldInfo.h" #include "Box2D/CCPhysicsWorldInfo.h" +#include "chipmunk/CCPhysicsShapeInfo.h" +#include "Box2D/CCPhysicsShapeInfo.h" #include "chipmunk/CCPhysicsHelper.h" #include "Box2D/CCPhysicsHelper.h" @@ -62,13 +64,15 @@ PhysicsBody::PhysicsBody() : _owner(nullptr) , _world(nullptr) , _info(nullptr) -, _dynamic(false) +, _dynamic(true) +, _enable(true) , _massDefault(true) , _angularDampingDefault(true) , _mass(MASS_DEFAULT) , _area(0.0) , _density(DENSITY_DEFAULT) , _angularDamping(ANGULARDAMPING_DEFAULT) +, _tag(0) { } @@ -76,10 +80,7 @@ PhysicsBody::~PhysicsBody() { CC_SAFE_DELETE(_info); - for (auto it = _shapes.begin(); it != _shapes.end(); ++it) - { - delete *it; - } + removeAllShapes(); for (auto it = _joints.begin(); it != _joints.end(); ++it) { @@ -91,12 +92,11 @@ PhysicsBody::~PhysicsBody() } } -PhysicsBody* PhysicsBody::createCircle(float radius) +PhysicsBody* PhysicsBody::create() { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addCircle(radius); body->autorelease(); return body; } @@ -105,12 +105,12 @@ PhysicsBody* PhysicsBody::createCircle(float radius) return nullptr; } -PhysicsBody* PhysicsBody::createBox(Size size) +PhysicsBody* PhysicsBody::createCircle(float radius, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addBox(size); + body->addShape(PhysicsShapeCircle::create(radius, material)); body->autorelease(); return body; } @@ -119,12 +119,12 @@ PhysicsBody* PhysicsBody::createBox(Size size) return nullptr; } -PhysicsBody* PhysicsBody::createPolygon(Point* points, int count) +PhysicsBody* PhysicsBody::createBox(Size size, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); if (body && body->init()) { - body->addPolygon(points, count); + body->addShape(PhysicsShapeBox::create(size, material)); body->autorelease(); return body; } @@ -133,12 +133,12 @@ PhysicsBody* PhysicsBody::createPolygon(Point* points, int count) return nullptr; } -PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1*/) +PhysicsBody* PhysicsBody::createPolygon(Point* points, int count, PhysicsMaterial material) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeSegment(a, b, border); + body->addShape(PhysicsShapePolygon::create(points, count, material)); body->autorelease(); return body; } @@ -147,27 +147,28 @@ PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, float border/* = 1 return nullptr; } -PhysicsBody* PhysicsBody::createEdgeBox(Size size, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgeSegment(Point a, Point b, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeBox(size, border); + body->addShape(PhysicsShapeEdgeSegment::create(a, b, material, border)); + body->_dynamic = false; body->autorelease(); return body; } CC_SAFE_DELETE(body); - return nullptr; } -PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgeBox(Size size, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgePolygon(points, count, border); + body->addShape(PhysicsShapeEdgeBox::create(size, material, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -177,12 +178,13 @@ PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, float bord return nullptr; } -PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border/* = 1*/) +PhysicsBody* PhysicsBody::createEdgePolygon(Point* points, int count, PhysicsMaterial material, float border/* = 1*/) { PhysicsBody* body = new PhysicsBody(); - if (body && body->initStatic()) + if (body && body->init()) { - body->addEdgeChain(points, count); + body->addShape(PhysicsShapeEdgePolygon::create(points, count, material, border)); + body->_dynamic = false; body->autorelease(); return body; } @@ -192,67 +194,20 @@ PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, float border return nullptr; } -PhysicsShapeCircle* PhysicsBody::addCircle(float radius, Point offset/* = Point(0, 0)*/) +PhysicsBody* PhysicsBody::createEdgeChain(Point* points, int count, PhysicsMaterial material, float border/* = 1*/) { - _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); - setMass((_massDefault ? 0 : getMass()) + _area * _density); + PhysicsBody* body = new PhysicsBody(); + if (body && body->init()) + { + body->addShape(PhysicsShapeEdgeChain::create(points, count, material, border)); + body->_dynamic = false; + body->autorelease(); + return body; + } - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForCircle(getMass(), 0, radius, PhysicsHelper::point2cpv(offset)))); + CC_SAFE_DELETE(body); - return PhysicsShapeCircle::create(this, radius, offset); -} - -PhysicsShapeBox* PhysicsBody::addBox(Size size, Point offset/* = Point(0, 0)*/) -{ - cpVect cpOffset = PhysicsHelper::size2cpv(size); - cpVect vec[4] = {}; - vec[0] = cpv(0, 0); - vec[1] = cpv(0, cpOffset.y); - vec[2] = cpv(cpOffset.x, cpOffset.y); - vec[3] = cpv(cpOffset.x, 0); - - _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(4, vec)); - setMass((_massDefault ? 0 : getMass()) + _area * _density); - - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForBox(getMass(), PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)))); - - return PhysicsShapeBox::create(this, size, offset); -} - -PhysicsShapePolygon* PhysicsBody::addPolygon(Point* points, int count, Point offset/* = Point(0, 0)*/) -{ - cpVect* vec = new cpVect[count]; - PhysicsHelper::points2cpvs(points, vec, count); - _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vec)); - - setAngularDamping((_angularDampingDefault ? 0 : getAngularDamping()) - + PhysicsHelper::cpfloat2float(cpMomentForPoly(getMass(), count, vec, PhysicsHelper::point2cpv(offset)))); - - delete[] vec; - - return PhysicsShapePolygon::create(this, points, count, offset); -} - -PhysicsShapeEdgeSegment* PhysicsBody::addEdgeSegment(Point a, Point b, float border/* = 1*/) -{ - return PhysicsShapeEdgeSegment::create(this, a, b, border); -} - -PhysicsShapeEdgeBox* PhysicsBody::addEdgeBox(Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) -{ - return PhysicsShapeEdgeBox::create(this, size, border, offset); -} - -PhysicsShapeEdgePolygon* PhysicsBody::addEdgePolygon(Point* points, int count, float border/* = 1*/) -{ - return PhysicsShapeEdgePolygon::create(this, points, count); -} - -PhysicsShapeEdgeChain* PhysicsBody::addEdgeChain(Point* points, int count, float border/* = 1*/) -{ - return PhysicsShapeEdgeChain::create(this, points, count, border); + return nullptr; } bool PhysicsBody::init() @@ -264,7 +219,6 @@ bool PhysicsBody::init() _info->body = cpBodyNew(PhysicsHelper::float2cpfloat(_mass), PhysicsHelper::float2cpfloat(_angularDamping)); CC_BREAK_IF(_info->body == nullptr); - _dynamic = true; return true; } while (false); @@ -274,36 +228,22 @@ bool PhysicsBody::init() void PhysicsBody::setDynamic(bool dynamic) { - _dynamic = dynamic; - if (_world != nullptr && cpBodyIsStatic(_info->body) == (cpBool)_dynamic) + if (dynamic != _dynamic) { if (dynamic) { - cpSpaceConvertBodyToDynamic(_world->_info->space, _info->body, _mass, _angularDamping); + cpBodySetMass(_info->body, PhysicsHelper::float2cpfloat(_mass)); + cpBodySetMoment(_info->body, PhysicsHelper::float2cpfloat(_angularDamping)); }else { - cpSpaceConvertBodyToStatic(_world->_info->space, _info->body); + cpBodySetMass(_info->body, PHYSICS_INFINITY); + cpBodySetMoment(_info->body, PHYSICS_INFINITY); } + + _dynamic = dynamic; } } -bool PhysicsBody::initStatic() -{ - do - { - _info = new PhysicsBodyInfo(); - CC_BREAK_IF(_info == nullptr); - - _info->body = cpBodyNewStatic(); - CC_BREAK_IF(_info->body == nullptr); - _dynamic = false; - - return true; - } while (false); - - return false; -} - void PhysicsBody::setPosition(Point position) { cpBodySetPos(_info->body, PhysicsHelper::point2cpv(position)); @@ -329,9 +269,79 @@ void PhysicsBody::addShape(PhysicsShape* shape) { if (shape == nullptr) return; - _shapes.push_back(shape); + // already added + if (shape->getBody() == this) + { + return; + } + else if (shape->getBody() != nullptr) + { + shape->getBody()->removeShape(shape); + } - if (_world != nullptr) _world->addShape(shape); + // reset the body + if (shape->_info->body != _info->body) + { + for (cpShape* subShape : shape->_info->shapes) + { + cpShapeSetBody(subShape, _info->body); + } + shape->_info->body = _info->body; + } + + // add shape to body + if (std::find(_shapes.begin(), _shapes.end(), shape) == _shapes.end()) + { + shape->setBody(this); + _shapes.push_back(shape); + + // calculate the mass, area and desity + _area += shape->getArea(); + if (_mass == PHYSICS_INFINITY || shape->getMass() == PHYSICS_INFINITY) + { + _mass = PHYSICS_INFINITY; + _massDefault = false; + }else + { + if (shape->getMass() > 0) + { + _mass = (_massDefault ? 0 : _mass) + shape->getMass(); + _massDefault = false; + } + } + cpBodySetMass(_info->body, _mass); + + if (!_massDefault) + { + if (_mass == PHYSICS_INFINITY) + { + _density = PHYSICS_INFINITY; + }else + { + _density = _mass / _area; + } + } + + if (shape->getAngularDumping() > 0) + { + if (shape->getAngularDumping() == INFINITY) + { + _angularDamping = INFINITY; + _angularDampingDefault = false; + cpBodySetMoment(_info->body, _angularDamping); + } + else if (_angularDamping != INFINITY) + { + _angularDamping = (_angularDampingDefault ? 0 : _angularDamping) + shape->getAngularDumping(); + _angularDampingDefault = false; + cpBodySetMoment(_info->body, _angularDamping); + } + } + + if (_world != nullptr) _world->addShape(shape); + + shape->retain(); + } } void PhysicsBody::applyForce(Point force) @@ -367,6 +377,16 @@ void PhysicsBody::setMass(float mass) cpBodySetMass(_info->body, PhysicsHelper::float2cpfloat(_mass)); } +void PhysicsBody::setVelocity(Point velocity) +{ + cpBodySetVel(_info->body, PhysicsHelper::point2cpv(velocity)); +} + +Point PhysicsBody::getVelocity() +{ + return PhysicsHelper::cpv2point(cpBodyGetVel(_info->body)); +} + void PhysicsBody::setAngularDamping(float angularDamping) { _angularDamping = angularDamping; @@ -375,6 +395,120 @@ void PhysicsBody::setAngularDamping(float angularDamping) cpBodySetMoment(_info->body, _angularDamping); } +PhysicsShape* PhysicsBody::getShapeByTag(int tag) +{ + for (auto shape : _shapes) + { + if (shape->getTag() == tag) + { + return shape; + } + } + + return nullptr; +} + +void PhysicsBody::removeShapeByTag(int tag) +{ + for (auto shape : _shapes) + { + if (shape->getTag() == tag) + { + removeShape(shape); + return; + } + } +} + +void PhysicsBody::removeShape(PhysicsShape* shape) +{ + auto it = std::find(_shapes.begin(), _shapes.end(), shape); + + if (it != _shapes.end()) + { + if (_world) + { + _world->removeShape(shape); + } + + _shapes.erase(it); + + + // deduce the mass, area and angularDamping + if (_mass != PHYSICS_INFINITY && shape->getMass() != PHYSICS_INFINITY) + { + if (_mass - shape->getMass() <= 0) + { + _mass = MASS_DEFAULT; + _massDefault = true; + }else + { + _mass = _mass = shape->getMass(); + } + + _area -= shape->getArea(); + + if (_mass == PHYSICS_INFINITY) + { + _density = PHYSICS_INFINITY; + } + else if (_area > 0) + { + _density = _mass / _area; + } + else + { + _density = DENSITY_DEFAULT; + } + + if (_angularDamping - shape->getAngularDumping() > 0) + { + _angularDamping -= shape->getAngularDumping(); + }else + { + _angularDamping = ANGULARDAMPING_DEFAULT; + _angularDampingDefault = true; + } + } + + shape->release(); + } +} + +void PhysicsBody::removeAllShapes() +{ + for (auto shape : _shapes) + { + if (_world) + { + _world->removeShape(shape); + } + + delete shape; + } + + _shapes.clear(); +} + +void PhysicsBody::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (_world) + { + if (enable) + { + _world->addBody(this); + }else + { + _world->removeBody(this); + } + } + } +} + //Clonable* PhysicsBody::clone() const //{ // PhysicsBody* body = new PhysicsBody(); diff --git a/cocos2dx/physics/CCPhysicsBody.h b/cocos2dx/physics/CCPhysicsBody.h index 515366e64e..9bfd9ece3e 100644 --- a/cocos2dx/physics/CCPhysicsBody.h +++ b/cocos2dx/physics/CCPhysicsBody.h @@ -30,22 +30,21 @@ #include "cocoa/CCObject.h" #include "cocoa/CCGeometry.h" + +#include "CCPhysicsShape.h" + #include NS_CC_BEGIN class Sprite; class PhysicsWorld; class PhysicsJoint; -class PhysicsShape; -class PhysicsShapeCircle; -class PhysicsShapeBox; -class PhysicsShapePolygon; -class PhysicsShapeEdgeSegment; -class PhysicsShapeEdgeBox; -class PhysicsShapeEdgePolygon; -class PhysicsShapeEdgeChain; class PhysicsBodyInfo; + + +const PhysicsMaterial PHYSICSBODY_MATERIAL_DEFAULT = {0.0f, 1.0f, 1.0f}; + /** * A body affect by physics. * it can attach one or more shapes. @@ -53,68 +52,39 @@ class PhysicsBodyInfo; class PhysicsBody : public Object//, public Clonable { public: + static PhysicsBody* create(); /** * @brief Create a body contains a circle shape. */ - static PhysicsBody* createCircle(float radius); + static PhysicsBody* createCircle(float radius, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a box shape. */ - static PhysicsBody* createBox(Size size); + static PhysicsBody* createBox(Size size, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a polygon shape. * points is an array of Point structs defining a convex hull with a clockwise winding. */ - static PhysicsBody* createPolygon(Point* points, int count); + static PhysicsBody* createPolygon(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT); /** * @brief Create a body contains a EdgeSegment shape. */ - static PhysicsBody* createEdgeSegment(Point a, Point b, float border = 1); + static PhysicsBody* createEdgeSegment(Point a, Point b, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgeBox shape. */ - static PhysicsBody* createEdgeBox(Size size, float border = 1); + static PhysicsBody* createEdgeBox(Size size, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgePolygon shape. */ - static PhysicsBody* createEdgePolygon(Point* points, int count, float border = 1); + static PhysicsBody* createEdgePolygon(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); /** * @brief Create a body contains a EdgeChain shape. */ - static PhysicsBody* createEdgeChain(Point* points, int count, float border = 1); + static PhysicsBody* createEdgeChain(Point* points, int count, PhysicsMaterial material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1); - /** - * @brief Attach a circle shape with body - */ - virtual PhysicsShapeCircle* addCircle(float radius, Point offset = Point(0, 0)); - /** - * @brief Attach a box shape with body - */ - virtual PhysicsShapeBox* addBox(Size size, Point offset = Point(0, 0)); - /** - * @brief Attach a polygon shape with body - */ - virtual PhysicsShapePolygon* addPolygon(Point* points, int count, Point offset = Point(0, 0)); - - /** - * @brief Attach a edge segment shape with body - */ - virtual PhysicsShapeEdgeSegment* addEdgeSegment(Point a, Point b, float border = 1); - /** - * @brief Attach a edge box shape with body - */ - virtual PhysicsShapeEdgeBox* addEdgeBox(Size size, float border = 1, Point offset = Point(0, 0)); - /** - * @brief Attach a edge polygon shape with body - * points is an array of Point structs defining a convex hull with a clockwise winding. - */ - virtual PhysicsShapeEdgePolygon* addEdgePolygon(Point* points, int count, float border = 1); - /** - * @brief Attach a edge chain shape with body - * points is an array of Point structs defining a convex hull with a clockwise winding. - */ - virtual PhysicsShapeEdgeChain* addEdgeChain(Point* points, int count, float border = 1); + virtual void addShape(PhysicsShape* shape); /** * @brief Applies a immediate force to body. @@ -137,6 +107,9 @@ public: */ virtual void applyTorque(float torque); + virtual void setVelocity(Point velocity); + virtual Point getVelocity(); + /* * @brief get the body shapes. */ @@ -145,10 +118,12 @@ public: * @brief get the first body shapes. */ inline PhysicsShape* getShape() { return _shapes.size() >= 1 ? _shapes.front() : nullptr; } + PhysicsShape* getShapeByTag(int tag); /* * @brief remove a shape from body */ void removeShape(PhysicsShape* shape); + void removeShapeByTag(int tag); /* * @brief remove all shapes */ @@ -215,14 +190,18 @@ public: //virtual Clonable* clone() const override; + inline bool isEnable() { return _enable; } + void setEnable(bool enable); + + inline int getTag() { return _tag; } + inline void setTag(int tag) { _tag = tag; } + protected: bool init(); - bool initStatic(); virtual void setPosition(Point position); virtual void setRotation(float rotation); - virtual void addShape(PhysicsShape* shape); protected: PhysicsBody(); @@ -235,12 +214,14 @@ protected: PhysicsWorld* _world; PhysicsBodyInfo* _info; bool _dynamic; + bool _enable; bool _massDefault; bool _angularDampingDefault; float _mass; float _area; float _density; float _angularDamping; + int _tag; int _categoryBitmask; int _contactTestBitmask; @@ -249,7 +230,7 @@ protected: friend class PhysicsWorld; friend class PhysicsShape; friend class PhysicsJoint; - friend class Sprite; + friend class Node; }; NS_CC_END diff --git a/cocos2dx/physics/CCPhysicsJoint.cpp b/cocos2dx/physics/CCPhysicsJoint.cpp index 3e60d246ab..63b6ac052e 100644 --- a/cocos2dx/physics/CCPhysicsJoint.cpp +++ b/cocos2dx/physics/CCPhysicsJoint.cpp @@ -46,6 +46,8 @@ PhysicsJoint::PhysicsJoint() : _bodyA(nullptr) , _bodyB(nullptr) , _info(nullptr) +, _enable(false) +, _tag(0) { } @@ -79,6 +81,21 @@ bool PhysicsJoint::init(cocos2d::PhysicsBody *a, cocos2d::PhysicsBody *b) return false; } +void PhysicsJoint::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (enable) + { + + }else + { + + } + } +} PhysicsJointPin::PhysicsJointPin() { diff --git a/cocos2dx/physics/CCPhysicsJoint.h b/cocos2dx/physics/CCPhysicsJoint.h index 854963049d..73383c39b6 100644 --- a/cocos2dx/physics/CCPhysicsJoint.h +++ b/cocos2dx/physics/CCPhysicsJoint.h @@ -49,6 +49,10 @@ protected: public: PhysicsBody* getBodyA() { return _bodyA; } PhysicsBody* getBodyB() { return _bodyB; } + inline int getTag() { return _tag; } + inline void setTag(int tag) { _tag = tag; } + inline bool isEnable() { return _enable; } + void setEnable(bool enable); protected: bool init(PhysicsBody* a, PhysicsBody* b); @@ -62,8 +66,11 @@ protected: PhysicsBody* _bodyA; PhysicsBody* _bodyB; PhysicsJointInfo* _info; + bool _enable; + int _tag; friend class PhysicsBody; + friend class PhysicsWorld; }; /* diff --git a/cocos2dx/physics/CCPhysicsSetting.h b/cocos2dx/physics/CCPhysicsSetting.h index 98b39f8f66..b29b12054d 100644 --- a/cocos2dx/physics/CCPhysicsSetting.h +++ b/cocos2dx/physics/CCPhysicsSetting.h @@ -43,4 +43,9 @@ #define CC_USE_PHYSICS #endif +namespace cocos2d +{ + extern const float PHYSICS_INFINITY; +} + #endif // __CCPHYSICS_SETTING_H__ diff --git a/cocos2dx/physics/CCPhysicsShape.cpp b/cocos2dx/physics/CCPhysicsShape.cpp index e98dff0b5c..b373e0710e 100644 --- a/cocos2dx/physics/CCPhysicsShape.cpp +++ b/cocos2dx/physics/CCPhysicsShape.cpp @@ -32,6 +32,7 @@ #endif #include "CCPhysicsBody.h" +#include "CCPhysicsWorld.h" #include "chipmunk/CCPhysicsBodyInfo.h" #include "Box2D/CCPhysicsBodyInfo.h" @@ -45,6 +46,11 @@ PhysicsShape::PhysicsShape() : _body(nullptr) , _info(nullptr) , _type(Type::UNKNOWN) +, _area(0) +, _mass(0) +, _angularDamping(0) +, _tag(0) +, _enable(true) { } @@ -54,20 +60,41 @@ PhysicsShape::~PhysicsShape() CC_SAFE_DELETE(_info); } -bool PhysicsShape::init(PhysicsBody* body, Type type) +bool PhysicsShape::init(Type type, PhysicsMaterial material/* = MaterialDefault*/) { - if (body == nullptr) return false; - - _body = body; - _info = new PhysicsShapeInfo(this); if (_info == nullptr) return false; _type = type; + _material = material; return true; } +void PhysicsShape::setMass(float mass) +{ + +} + +void PhysicsShape::setEnable(bool enable) +{ + if (_enable != enable) + { + _enable = enable; + + if (_body->getWorld() && _body->isEnable()) + { + if (enable) + { + _body->getWorld()->addShape(this); + }else + { + _body->getWorld()->removeShape(this); + } + } + } +} + void PhysicsShape::addToBody() { if(_body != nullptr) _body->addShape(this); @@ -75,7 +102,13 @@ void PhysicsShape::addToBody() PhysicsBodyInfo* PhysicsShape::bodyInfo() const { - return _body->_info; + if (_body != nullptr) + { + return _body->_info; + }else + { + return nullptr; + } } PhysicsShapeCircle::PhysicsShapeCircle() @@ -150,12 +183,38 @@ PhysicsShapeEdgeSegment::~PhysicsShapeEdgeSegment() #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +void PhysicsShape::initEnd() +{ + for (auto shape : _info->shapes) + { + cpShapeSetElasticity(shape, _material.elasticity); + cpShapeSetFriction(shape, _material.friction); + } +} + +void PhysicsShape::setElasticity(float elasticity) +{ + for (cpShape* shape : _info->shapes) + { + cpShapeSetElasticity(shape, PhysicsHelper::float2cpfloat(elasticity)); + } +} + +void PhysicsShape::setFriction(float friction) +{ + for (cpShape* shape : _info->shapes) + { + cpShapeSetFriction(shape, PhysicsHelper::float2cpfloat(friction)); + } +} + // PhysicsShapeCircle -PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, Point offset/* = Point(0, 0)*/) +PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeCircle* shape = new PhysicsShapeCircle(); - if (shape && shape->init(body, radius, offset)) + if (shape && shape->init(radius, material, offset)) { + shape->autorelease(); return shape; } @@ -163,19 +222,23 @@ PhysicsShapeCircle* PhysicsShapeCircle::create(PhysicsBody* body, float radius, return nullptr; } -bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeCircle::init(float radius, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::CIRCLE)); + CC_BREAK_IF(!PhysicsShape::init(Type::CIRCLE, material)); - cpShape* shape = cpCircleShapeNew(bodyInfo()->body, radius, PhysicsHelper::point2cpv(offset)); + cpShape* shape = cpCircleShapeNew(_info->shareBody, radius, PhysicsHelper::point2cpv(offset)); CC_BREAK_IF(shape == nullptr); - _info->add(shape); - addToBody(); + _area = PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius)); + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForCircle(_mass, 0, radius, PhysicsHelper::point2cpv(offset)); + _info->add(shape); + + initEnd(); return true; } while (false); @@ -183,11 +246,12 @@ bool PhysicsShapeCircle::init(PhysicsBody* body, float radius, Point offset /*= } // PhysicsShapeEdgeSegment -PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(PhysicsBody* body, Point a, Point b, float border/* = 1*/) +PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(Point a, Point b, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgeSegment* shape = new PhysicsShapeEdgeSegment(); - if (shape && shape->init(body, a, b, border)) + if (shape && shape->init(a, b, material, border)) { + shape->autorelease(); return shape; } @@ -195,21 +259,25 @@ PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(PhysicsBody* body, Poin return nullptr; } -bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float border/* = 1*/) +bool PhysicsShapeEdgeSegment::init(Point a, Point b, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGESEGMENT)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGESEGMENT, material)); - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, + cpShape* shape = cpSegmentShapeNew(_info->shareBody, PhysicsHelper::point2cpv(a), PhysicsHelper::point2cpv(b), PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; + _info->add(shape); - addToBody(); + + initEnd(); return true; } while (false); @@ -218,11 +286,12 @@ bool PhysicsShapeEdgeSegment::init(PhysicsBody* body, Point a, Point b, float bo } // PhysicsShapeBox -PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, Point offset/* = Point(0, 0)*/) +PhysicsShapeBox* PhysicsShapeBox::create(Size size, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeBox* shape = new PhysicsShapeBox(); - if (shape && shape->init(body, size, offset)) + if (shape && shape->init(size, material, offset)) { + shape->autorelease(); return shape; } @@ -230,18 +299,23 @@ PhysicsShapeBox* PhysicsShapeBox::create(PhysicsBody* body, Size size, Point off return nullptr; } -bool PhysicsShapeBox::init(PhysicsBody* body, Size size, Point offset /*= Point(0, 0)*/) +bool PhysicsShapeBox::init(Size size, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::BOX)); + CC_BREAK_IF(!PhysicsShape::init(Type::BOX, material)); - cpShape* shape = cpBoxShapeNew(bodyInfo()->body, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); + cpShape* shape = cpBoxShapeNew(_info->shareBody, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); CC_BREAK_IF(shape == nullptr); + _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(4, ((cpPolyShape*)shape)->verts)); + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForBox(_mass, PhysicsHelper::float2cpfloat(size.width), PhysicsHelper::float2cpfloat(size.height)); + _info->add(shape); - addToBody(); + + initEnd(); return true; } while (false); @@ -250,11 +324,12 @@ bool PhysicsShapeBox::init(PhysicsBody* body, Size size, Point offset /*= Point( } // PhysicsShapeCircle -PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* points, int count, Point offset/* = Point(0, 0)*/) +PhysicsShapePolygon* PhysicsShapePolygon::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, Point offset/* = Point(0, 0)*/) { PhysicsShapePolygon* shape = new PhysicsShapePolygon(); - if (shape && shape->init(body, points, count, offset)) + if (shape && shape->init(points, count, material, offset)) { + shape->autorelease(); return shape; } @@ -262,20 +337,26 @@ PhysicsShapePolygon* PhysicsShapePolygon::create(PhysicsBody* body, Point* point return nullptr; } -bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, Point offset /*= Point(0, 0)*/) +bool PhysicsShapePolygon::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, Point offset /*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::POLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::POLYGEN, material)); cpVect* vecs = new cpVect[count]; PhysicsHelper::points2cpvs(points, vecs, count); - cpShape* shape = cpPolyShapeNew(bodyInfo()->body, count, vecs, PhysicsHelper::point2cpv(offset)); + cpShape* shape = cpPolyShapeNew(_info->shareBody, count, vecs, PhysicsHelper::point2cpv(offset)); + CC_SAFE_DELETE(vecs); CC_BREAK_IF(shape == nullptr); + _area = PhysicsHelper::cpfloat2float(cpAreaForPoly(((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts)); + _mass = _material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : _material.density * _area; + _angularDamping = _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY : cpMomentForPoly(_mass, ((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts, PhysicsHelper::point2cpv(offset)); + _info->add(shape); - addToBody(); + + initEnd(); return true; } while (false); @@ -284,11 +365,12 @@ bool PhysicsShapePolygon::init(PhysicsBody* body, Point* points, int count, Poin } // PhysicsShapeEdgeBox -PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(PhysicsBody* body, Size size, float border/* = 1*/, Point offset/* = Point(0, 0)*/) +PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(Size size, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/, Point offset/* = Point(0, 0)*/) { PhysicsShapeEdgeBox* shape = new PhysicsShapeEdgeBox(); - if (shape && shape->init(body, size, border, offset)) + if (shape && shape->init(size, material, border, offset)) { + shape->autorelease(); return shape; } @@ -296,33 +378,32 @@ PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(PhysicsBody* body, Size size, f return nullptr; } -bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1*/, Point offset/*= Point(0, 0)*/) +bool PhysicsShapeEdgeBox::init(Size size, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/, Point offset/*= Point(0, 0)*/) { do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGEBOX)); - - Point bodyPos = body->getPosition(); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEBOX, material)); cpVect vec[4] = {}; - vec[0] = PhysicsHelper::point2cpv(Point(bodyPos.x-size.width/2+offset.x, bodyPos.y-size.height/2+offset.y)); - vec[1] = PhysicsHelper::point2cpv(Point(bodyPos.x+size.width/2+offset.x, bodyPos.y-size.height/2+offset.y)); - vec[2] = PhysicsHelper::point2cpv(Point(bodyPos.x+size.width/2+offset.x, bodyPos.y+size.height/2+offset.y)); - vec[3] = PhysicsHelper::point2cpv(Point(bodyPos.x-size.width/2+offset.x, bodyPos.y+size.height/2+offset.y)); + vec[0] = PhysicsHelper::point2cpv(Point(-size.width/2+offset.x, -size.height/2+offset.y)); + vec[1] = PhysicsHelper::point2cpv(Point(+size.width/2+offset.x, -size.height/2+offset.y)); + vec[2] = PhysicsHelper::point2cpv(Point(+size.width/2+offset.x, +size.height/2+offset.y)); + vec[3] = PhysicsHelper::point2cpv(Point(-size.width/2+offset.x, +size.height/2+offset.y)); int i = 0; for (; i < 4; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[(i+1)%4], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[(i+1)%4], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); - cpShapeSetElasticity(shape, 1.0f); - cpShapeSetFriction(shape, 1.0f); _info->add(shape); } CC_BREAK_IF(i < 4); - addToBody(); + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; + + initEnd(); return true; } while (false); @@ -331,11 +412,12 @@ bool PhysicsShapeEdgeBox::init(PhysicsBody* body, Size size, float border/* = 1* } // PhysicsShapeEdgeBox -PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgePolygon* shape = new PhysicsShapeEdgePolygon(); - if (shape && shape->init(body, points, count, border)) - { + if (shape && shape->init(points, count, material, border)) + { + shape->autorelease(); return shape; } @@ -343,12 +425,12 @@ PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(PhysicsBody* body, Poin return nullptr; } -bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgePolygon::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGEPOLYGEN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGEPOLYGEN, material)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -356,18 +438,22 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, int i = 0; for (; i < count; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[(i+1)%count], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[(i+1)%count], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); _info->add(shape); } + CC_SAFE_DELETE(vec); + CC_BREAK_IF(i < count); - addToBody(); + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; + + initEnd(); - if (vec != nullptr) delete[] vec; return true; } while (false); @@ -377,11 +463,12 @@ bool PhysicsShapeEdgePolygon::init(PhysicsBody* body, Point* points, int count, } // PhysicsShapeEdgeChain -PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { PhysicsShapeEdgeChain* shape = new PhysicsShapeEdgeChain(); - if (shape && shape->init(body, points, count, border)) + if (shape && shape->init(points, count, material, border)) { + shape->autorelease(); return shape; } @@ -389,12 +476,12 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(PhysicsBody* body, Point* p return nullptr; } -bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, float border/* = 1*/) +bool PhysicsShapeEdgeChain::init(Point* points, int count, PhysicsMaterial material/* = MaterialDefault*/, float border/* = 1*/) { cpVect* vec = nullptr; do { - CC_BREAK_IF(!PhysicsShape::init(body, Type::EDGECHAIN)); + CC_BREAK_IF(!PhysicsShape::init(Type::EDGECHAIN, material)); vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); @@ -402,18 +489,21 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl int i = 0; for (; i < count - 1; ++i) { - cpShape* shape = cpSegmentShapeNew(bodyInfo()->body, vec[i], vec[i+1], + cpShape* shape = cpSegmentShapeNew(_info->shareBody, vec[i], vec[i+1], PhysicsHelper::float2cpfloat(border)); CC_BREAK_IF(shape == nullptr); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); _info->add(shape); } + if (vec != nullptr) delete[] vec; CC_BREAK_IF(i < count); - addToBody(); + _mass = PHYSICS_INFINITY; + _angularDamping = PHYSICS_INFINITY; + + initEnd(); - if (vec != nullptr) delete[] vec; return true; } while (false); @@ -422,7 +512,6 @@ bool PhysicsShapeEdgeChain::init(PhysicsBody* body, Point* points, int count, fl return false; } - #elif (CC_PHYSICS_ENGINE == CC_PHYSICS_BOX2D) #endif diff --git a/cocos2dx/physics/CCPhysicsShape.h b/cocos2dx/physics/CCPhysicsShape.h index 79cda68e6d..d754f6030b 100644 --- a/cocos2dx/physics/CCPhysicsShape.h +++ b/cocos2dx/physics/CCPhysicsShape.h @@ -37,7 +37,27 @@ class PhysicsShapeInfo; class PhysicsBody; class PhysicsBodyInfo; -/** + +typedef struct PhysicsMaterial +{ + float density; + float elasticity; + float friction; + + PhysicsMaterial() + : density(0.0f) + , elasticity(0.0f) + , friction(0.0f){} + + PhysicsMaterial(float density, float elasticity, float friction) + : density(density) + , elasticity(elasticity) + , friction(friction){} +}PhysicsMaterial; + +const PhysicsMaterial PHYSICSSHAPE_MATERIAL_DEFAULT = {0.0f, 1.0f, 1.0f}; + +/** * @brief A shape for body. You do not create PhysicsWorld objects directly, instead, you can view PhysicsBody to see how to create it. */ class PhysicsShape : public Object @@ -58,16 +78,32 @@ public: public: inline PhysicsBody* getBody(){ return _body; } inline Type getType() { return _type; } + inline float getArea() { return _area; } + inline float getAngularDumping() { return _angularDamping; } + void setAngularDumping(float angularDumping); + inline void setTag(int tag) { _tag = tag; } + inline int getTag() { return _tag; } + void setEnable(bool enable); + inline bool isEnable() { return _enable; } + void addToBody(); + + inline float getMass() { return _mass; } + void setMass(float mass); + inline float getDensity() { return _material.density; } + void setDensity(float density); + void setElasticity(float elasticity); + void setFriction(float friction); protected: - bool init(PhysicsBody* body, Type type); + bool init(Type type, PhysicsMaterial material); + void initEnd(); /** * @brief PhysicsShape is PhysicsBody's friend class, but all the subclasses isn't. so this method is use for subclasses to catch the bodyInfo from PhysicsBody. */ PhysicsBodyInfo* bodyInfo() const; - void addToBody(); + inline void setBody(PhysicsBody* body) { _body = body; } protected: PhysicsShape(); @@ -77,6 +113,12 @@ protected: PhysicsBody* _body; PhysicsShapeInfo* _info; Type _type; + float _area; + float _mass; + float _angularDamping; + PhysicsMaterial _material; + int _tag; + bool _enable; friend class PhysicsWorld; friend class PhysicsBody; @@ -85,9 +127,11 @@ protected: /** A circle shape */ class PhysicsShapeCircle : public PhysicsShape { +public: + static PhysicsShapeCircle* create(float radius, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); + protected: - static PhysicsShapeCircle* create(PhysicsBody* body, float radius, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, float radius, Point offset = Point(0, 0)); + bool init(float radius, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapeCircle(); @@ -99,9 +143,11 @@ protected: /** A box shape */ class PhysicsShapeBox : public PhysicsShape { +public: + static PhysicsShapeBox* create(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); + protected: - static PhysicsShapeBox* create(PhysicsBody* body, Size size, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, Size size, Point offset = Point(0, 0)); + bool init(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapeBox(); @@ -113,9 +159,11 @@ protected: /** A polygon shape */ class PhysicsShapePolygon : public PhysicsShape { +public: + static PhysicsShapePolygon* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); + protected: - static PhysicsShapePolygon* create(PhysicsBody* body, Point* points, int count, Point offset = Point(0, 0)); - bool init(PhysicsBody* body, Point* points, int count, Point offset = Point(0, 0)); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, Point offset = Point(0, 0)); protected: PhysicsShapePolygon(); @@ -127,9 +175,11 @@ protected: /** A segment shape */ class PhysicsShapeEdgeSegment : public PhysicsShape { +public: + static PhysicsShapeEdgeSegment* create(Point a, Point b, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); + protected: - static PhysicsShapeEdgeSegment* create(PhysicsBody* body, Point a, Point b, float border = 1); - bool init(PhysicsBody* body, Point a, Point b, float border = 1); + bool init(Point a, Point b, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgeSegment(); @@ -142,10 +192,10 @@ protected: class PhysicsShapeEdgeBox : public PhysicsShape { public: - static PhysicsShapeEdgeBox* create(PhysicsBody* body, Size size, float border = 0, Point offset = Point(0, 0)); + static PhysicsShapeEdgeBox* create(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 0, Point offset = Point(0, 0)); protected: - bool init(PhysicsBody* body, Size size, float border = 1, Point offset = Point(0, 0)); + bool init(Size size, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1, Point offset = Point(0, 0)); protected: PhysicsShapeEdgeBox(); @@ -158,10 +208,10 @@ protected: class PhysicsShapeEdgePolygon : public PhysicsShape { public: - static PhysicsShapeEdgePolygon* create(PhysicsBody* body, Point* points, int count, float border = 1); + static PhysicsShapeEdgePolygon* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: - bool init(PhysicsBody* body, Point* points, int count, float border = 1); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgePolygon(); @@ -174,10 +224,10 @@ protected: class PhysicsShapeEdgeChain : public PhysicsShape { public: - static PhysicsShapeEdgeChain* create(PhysicsBody* body, Point* points, int count, float border = 1); + static PhysicsShapeEdgeChain* create(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: - bool init(PhysicsBody* body, Point* points, int count, float border = 1); + bool init(Point* points, int count, PhysicsMaterial material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); protected: PhysicsShapeEdgeChain(); diff --git a/cocos2dx/physics/CCPhysicsWorld.cpp b/cocos2dx/physics/CCPhysicsWorld.cpp index 5b714447d0..7ede980f53 100644 --- a/cocos2dx/physics/CCPhysicsWorld.cpp +++ b/cocos2dx/physics/CCPhysicsWorld.cpp @@ -34,6 +34,7 @@ #include "CCPhysicsBody.h" #include "CCPhysicsShape.h" #include "CCPhysicsContact.h" +#include "CCPhysicsJoint.h" #include "chipmunk/CCPhysicsWorldInfo.h" #include "Box2D/CCPhysicsWorldInfo.h" @@ -43,6 +44,8 @@ #include "Box2D/CCPhysicsShapeInfo.h" #include "chipmunk/CCPhysicsContactInfo.h" #include "Box2D/CCPhysicsContactInfo.h" +#include "chipmunk/CCPhysicsJointInfo.h" +#include "Box2D/CCPhysicsJointInfo.h" #include "chipmunk/CCPhysicsHelper.h" #include "draw_nodes/CCDrawNode.h" @@ -50,10 +53,14 @@ #include "layers_scenes_transitions_nodes/CCScene.h" #include "CCDirector.h" +#include + NS_CC_BEGIN #if (CC_PHYSICS_ENGINE == CC_PHYSICS_CHIPMUNK) +const float PHYSICS_INFINITY = INFINITY; + int PhysicsWorld::collisionBeginCallbackFunc(cpArbiter *arb, struct cpSpace *space, void *data) { PhysicsWorld* world = static_cast(data); @@ -110,34 +117,69 @@ bool PhysicsWorld::init() return true; } +void PhysicsWorld::addJoint(PhysicsJoint* joint) +{ + auto it = std::find(_joints.begin(), _joints.end(), joint); + + if (it == _joints.end()) + { + _joints.push_back(joint); + + if (!cpSpaceContainsConstraint(_info->space, joint->_info->joint)) + { + cpSpaceAddConstraint(_info->space, joint->_info->joint); + } + } + +} + +void PhysicsWorld::removeJoint(PhysicsJoint* joint) +{ + +} + +void PhysicsWorld::removeAllJoints() +{ + +} + void PhysicsWorld::addShape(PhysicsShape* shape) { - for (auto it = shape->_info->shapes.begin(); it != shape->_info->shapes.end(); it++) + for (auto cps : shape->_info->shapes) { + if (cpSpaceContainsShape(_info->space, cps)) + { + continue; + } + if (cpBodyIsStatic(shape->getBody()->_info->body)) { - cpSpaceAddStaticShape(_info->space, *it); + cpSpaceAddStaticShape(_info->space, cps); }else { - cpSpaceAddShape(_info->space, *it); + cpSpaceAddShape(_info->space, cps); } } } -void PhysicsWorld::addChild(PhysicsBody* body) +void PhysicsWorld::addBody(PhysicsBody* body) { - auto shapes = body->getShapes(); - - // add body to space - if (body->isDynamic()) + if (body->isEnable()) { - cpSpaceAddBody(_info->space, body->_info->body); - } - - // add shapes to space - for (auto it = shapes.begin(); it != shapes.end(); it++) - { - addShape(*it); + // add body to space + if (body->isDynamic()) + { + cpSpaceAddBody(_info->space, body->_info->body); + } + + // add shapes to space + for (auto shape : body->getShapes()) + { + if (shape->isEnable()) + { + addShape(shape); + } + } } if (_bodys == nullptr) @@ -150,6 +192,54 @@ void PhysicsWorld::addChild(PhysicsBody* body) } } +void PhysicsWorld::removeBody(PhysicsBody* body) +{ + for (auto shape : body->getShapes()) + { + for (auto cps : shape->_info->shapes) + { + if (cpSpaceContainsShape(_info->space, cps)) + { + cpSpaceRemoveShape(_info->space, cps); + } + } + } + + if (cpSpaceContainsBody(_info->space, body->_info->body)) + { + cpSpaceRemoveBody(_info->space, body->_info->body); + } + + if (_bodys != nullptr) + { + _bodys->removeObject(body); + } +} + +void PhysicsWorld::removeBodyByTag(int tag) +{ + for (Object* obj : *_bodys) + { + PhysicsBody* body = dynamic_cast(obj); + if (body->getTag() == tag) + { + removeBody(body); + return; + } + } +} + +void PhysicsWorld::removeShape(PhysicsShape* shape) +{ + for (auto cps : shape->_info->shapes) + { + if (cpSpaceContainsShape(_info->space, cps)) + { + cpSpaceRemoveShape(_info->space, cps); + } + } +} + void PhysicsWorld::update(float delta) { cpSpaceStep(_info->space, delta); @@ -171,17 +261,16 @@ void PhysicsWorld::debugDraw() if (_debugDraw && _bodys != nullptr) { _drawNode= DrawNode::create(); - - Object* child = nullptr; - CCARRAY_FOREACH(_bodys, child) + + for (Object* obj : *_bodys) { - PhysicsBody* body = dynamic_cast(child); + PhysicsBody* body = dynamic_cast(obj); std::vector shapes = body->getShapes(); - for (auto it = shapes.begin(); it != shapes.end(); ++it) + for (auto shape : shapes) { - drawWithShape(_drawNode, *it); + drawWithShape(_drawNode, shape); } } @@ -195,7 +284,6 @@ void PhysicsWorld::debugDraw() void PhysicsWorld::setScene(Scene *scene) { _scene = scene; - scene->retain(); } void PhysicsWorld::drawWithShape(DrawNode* node, PhysicsShape* shape) @@ -322,7 +410,6 @@ PhysicsWorld::~PhysicsWorld() { CC_SAFE_DELETE(_info); CC_SAFE_RELEASE(_bodys); - CC_SAFE_RELEASE(_scene); } NS_CC_END diff --git a/cocos2dx/physics/CCPhysicsWorld.h b/cocos2dx/physics/CCPhysicsWorld.h index bd06fdf661..d7a30f37cf 100644 --- a/cocos2dx/physics/CCPhysicsWorld.h +++ b/cocos2dx/physics/CCPhysicsWorld.h @@ -28,6 +28,8 @@ #ifndef __CCPHYSICS_WORLD_H__ #define __CCPHYSICS_WORLD_H__ +#include + #include "cocoa/CCObject.h" #include "cocoa/CCGeometry.h" @@ -86,14 +88,18 @@ public: /** set the debug draw */ inline void setDebugDraw(bool debugDraw) { _debugDraw = debugDraw; } + virtual void removeBody(PhysicsBody* body); + virtual void removeBodyByTag(int tag); + protected: static PhysicsWorld* create(); bool init(); void setScene(Scene* scene); - virtual void addChild(PhysicsBody* body); + virtual void addBody(PhysicsBody* body); virtual void addShape(PhysicsShape* shape); + virtual void removeShape(PhysicsShape* shape); virtual void update(float delta); virtual void debugDraw(); @@ -120,6 +126,7 @@ protected: Array* _bodys; + std::list _joints; Scene* _scene; bool _debugDraw; @@ -132,6 +139,7 @@ protected: friend class Sprite; friend class Scene; friend class PhysicsBody; + friend class PhysicsShape; }; NS_CC_END diff --git a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp index 0734bf6e49..0c048c780b 100644 --- a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp +++ b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.cpp @@ -28,20 +28,27 @@ NS_CC_BEGIN std::map PhysicsShapeInfo::map; +cpBody* PhysicsShapeInfo::shareBody = nullptr; PhysicsShapeInfo::PhysicsShapeInfo(PhysicsShape* shape) : shape(shape) { + if (shareBody == nullptr) + { + shareBody = cpBodyNewStatic(); + } + + body = shareBody; } PhysicsShapeInfo::~PhysicsShapeInfo() { - for (auto it = shapes.begin(); it != shapes.end(); it++) + for (auto shape : shapes) { - cpShapeFree(*it); + auto it = map.find(shape); + if (it != map.end()) map.erase(shape); - auto mit = map.find(*it); - if (mit != map.end()) map.erase(*it); + cpShapeFree(shape); } } diff --git a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h index 7e0be63747..5e9f2a73e3 100644 --- a/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h +++ b/cocos2dx/physics/chipmunk/CCPhysicsShapeInfo.h @@ -46,8 +46,10 @@ public: public: std::vector shapes; - static std::map map; PhysicsShape* shape; + cpBody* body; + static std::map map; + static cpBody* shareBody; private: PhysicsShapeInfo(PhysicsShape* shape); diff --git a/cocos2dx/sprite_nodes/CCSprite.cpp b/cocos2dx/sprite_nodes/CCSprite.cpp index 741a1e1683..e1cfd9b5da 100644 --- a/cocos2dx/sprite_nodes/CCSprite.cpp +++ b/cocos2dx/sprite_nodes/CCSprite.cpp @@ -296,18 +296,12 @@ Sprite* Sprite::initWithCGImage(CGImageRef pImage, const char *pszKey) Sprite::Sprite(void) : _shouldBeHidden(false) , _texture(nullptr) -#ifdef CC_USE_PHYSICS -, _physicsBody(nullptr) -#endif { } Sprite::~Sprite(void) { CC_SAFE_RELEASE(_texture); -#ifdef CC_USE_PHYSICS - CC_SAFE_RELEASE(_physicsBody); -#endif } void Sprite::setTextureRect(const Rect& rect) @@ -790,13 +784,6 @@ void Sprite::setPosition(const Point& pos) { Node::setPosition(pos); SET_DIRTY_RECURSIVELY(); - -#ifdef CC_USE_PHYSICS - if (_physicsBody) - { - _physicsBody->setPosition(pos); - } -#endif } void Sprite::setRotation(float rotation) @@ -804,13 +791,6 @@ void Sprite::setRotation(float rotation) Node::setRotation(rotation); SET_DIRTY_RECURSIVELY(); - -#ifdef CC_USE_PHYSICS - if (_physicsBody) - { - _physicsBody->setRotation(rotation); - } -#endif } void Sprite::setRotationX(float fRotationX) @@ -907,33 +887,6 @@ bool Sprite::isFlippedY(void) const return _flippedY; } -#ifdef CC_USE_PHYSICS -void Sprite::setPhysicsBody(PhysicsBody* body) -{ - _physicsBody = body; - _physicsBody->retain(); - _physicsBody->setPosition(getPosition()); - _physicsBody->setRotation(getRotation()); -} - -PhysicsBody* Sprite::getPhysicsBody() const -{ - return _physicsBody; -} - -void Sprite::visit() -{ - if (_physicsBody) - { - Node::setPosition(_physicsBody->getPosition()); - Node::setRotation(_physicsBody->getRotation()); - SET_DIRTY_RECURSIVELY(); - } - - Node::visit(); -} -#endif //CC_USE_PHYSICS - // // RGBA protocol // diff --git a/cocos2dx/sprite_nodes/CCSprite.h b/cocos2dx/sprite_nodes/CCSprite.h index 815cd67614..d150c55213 100644 --- a/cocos2dx/sprite_nodes/CCSprite.h +++ b/cocos2dx/sprite_nodes/CCSprite.h @@ -461,20 +461,6 @@ public: */ void setFlippedY(bool flippedY); -#ifdef CC_USE_PHYSICS - /** - * set the PhysicsBody that let the sprite effect with physics - */ - virtual void setPhysicsBody(PhysicsBody* body); - - /** - * get the PhysicsBody the sprite have - */ - PhysicsBody* getPhysicsBody() const; - - virtual void visit() override; -#endif - /// @} End of Sprite properties getter/setters /** @deprecated Use isFlippedY() instead */ @@ -590,10 +576,6 @@ protected: // image is flipped bool _flippedX; /// Whether the sprite is flipped horizaontally or not. bool _flippedY; /// Whether the sprite is flipped vertically or not. - -#ifdef CC_USE_PHYSICS - PhysicsBody* _physicsBody; ///< the physicsBody the node have -#endif }; diff --git a/cocos2dx/sprite_nodes/CCSpriteBatchNode.cpp b/cocos2dx/sprite_nodes/CCSpriteBatchNode.cpp index 08120d339f..6df8215bd0 100644 --- a/cocos2dx/sprite_nodes/CCSpriteBatchNode.cpp +++ b/cocos2dx/sprite_nodes/CCSpriteBatchNode.cpp @@ -40,6 +40,8 @@ THE SOFTWARE. #include "CCDirector.h" #include "support/TransformUtils.h" #include "support/CCProfiling.h" +#include "layers_scenes_transitions_nodes/CCLayer.h" +#include "layers_scenes_transitions_nodes/CCScene.h" // external #include "kazmath/GL/matrix.h" @@ -180,6 +182,17 @@ void SpriteBatchNode::addChild(Node *child, int zOrder, int tag) Node::addChild(child, zOrder, tag); appendChild(sprite); + + + if (this->getParent() && + dynamic_cast(this->getParent()) != nullptr) + { + if (this->getParent()->getParent() && + dynamic_cast(this->getParent()->getParent())) + { + dynamic_cast(this->getParent()->getParent())->addChildToPhysicsWorld(child); + } + } } // override reorderChild diff --git a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp index 94f63e7f59..0ab5ba4ae4 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.cpp @@ -2,39 +2,204 @@ #include "../testResource.h" USING_NS_CC; -PhysicsTestLayer::PhysicsTestLayer() -: _spriteTexture(nullptr) -, _scene(nullptr) +namespace { + static std::function createFunctions[] = { + CL(PhysicsDemoLogoSmash), + CL(PhysicsDemoPyramidStack), + CL(PhysicsDemoPlink), + CL(PhysicsDemoClickAdd), + }; + + static int sceneIdx=-1; +#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) + + static Layer* next() + { + sceneIdx++; + sceneIdx = sceneIdx % MAX_LAYER; + + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } + + static Layer* back() + { + sceneIdx--; + int total = MAX_LAYER; + if( sceneIdx < 0 ) + sceneIdx += total; + + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } + + static Layer* restart() + { + auto layer = (createFunctions[sceneIdx])(); + layer->init(); + layer->autorelease(); + + return layer; + } +} + + +bool PhysicsTestScene::_debugDraw = false; + +bool PhysicsTestScene::initTest() +{ +#ifdef CC_USE_PHYSICS + if(TestScene::initWithPhysics()) + { + this->getPhysicsWorld()->setDebugDraw(_debugDraw); + return true; + } +#else + return TestScene::init(); +#endif + + return false; +} + +void PhysicsTestScene::runThisTest() +{ +#ifdef CC_USE_PHYSICS + sceneIdx = -1; + addChild(next()); + + Director::getInstance()->replaceScene(this); +#else +#endif +} + +void PhysicsTestScene::toggleDebug() +{ + _debugDraw = !_debugDraw; + getPhysicsWorld()->setDebugDraw(_debugDraw); +} + +PhysicsDemo::PhysicsDemo() +: _scene(nullptr) +{ + +} + +PhysicsDemo::~PhysicsDemo() +{ + +} + +std::string PhysicsDemo::title() +{ + return "PhysicsTest"; +} + +std::string PhysicsDemo::subtitle() +{ + return ""; +} + +void PhysicsDemo::restartCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->initTest(); + s->addChild( restart() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::nextCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->initTest(); + s->addChild( next() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::backCallback(Object* sender) +{ + auto s = new PhysicsTestScene(); + s->initTest(); + s->addChild( back() ); + Director::getInstance()->replaceScene(s); + s->release(); +} + +void PhysicsDemo::onEnter() +{ + BaseTest::onEnter(); + + _scene = dynamic_cast(this->getParent()); + + _spriteTexture = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100)->getTexture(); + +#ifdef CC_USE_PHYSICS + + // menu for debug layer + MenuItemFont::setFontSize(18); + auto item = MenuItemFont::create("Toggle debug", CC_CALLBACK_1(PhysicsDemo::toggleDebugCallback, this)); + + auto menu = Menu::create(item, NULL); + this->addChild(menu); + menu->setPosition(Point(VisibleRect::right().x-50, VisibleRect::top().y-10)); +#else +#endif +} + +void PhysicsDemo::addGrossiniAtPosition(Point p, float scale/* = 1.0*/) +{ +#ifdef CC_USE_PHYSICS + CCLOG("Add sprite %0.2f x %02.f",p.x,p.y); + + int posx, posy; + + posx = CCRANDOM_0_1() * 200.0f; + posy = CCRANDOM_0_1() * 200.0f; + + posx = (posx % 4) * 85; + posy = (posy % 3) * 121; + + auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121)); + sp->setScale(scale); + sp->setPhysicsBody(PhysicsBody::createBox(Size(48.0f * scale, 108.0f * scale))); + this->addChild(sp); + sp->setPosition(p); +#endif +} + + +void PhysicsDemo::toggleDebugCallback(Object* sender) +{ +#ifdef CC_USE_PHYSICS + if (_scene != nullptr) + { + _scene->toggleDebug(); + } +#endif +} + +void PhysicsDemoClickAdd::onEnter() +{ + PhysicsDemo::onEnter(); + #ifdef CC_USE_PHYSICS setTouchEnabled(true); setAccelerometerEnabled(true); - // title - auto label = LabelTTF::create("Multi touch the screen", "Marker Felt", 36); - label->setPosition(Point( VisibleRect::center().x, VisibleRect::top().y - 30)); - this->addChild(label, -1); + auto node = Node::create(); + node->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size)); + node->setPosition(VisibleRect::center()); + this->addChild(node); - // menu for debug layer - MenuItemFont::setFontSize(18); - auto item = MenuItemFont::create("Toggle debug", CC_CALLBACK_1(PhysicsTestLayer::toggleDebugCallback, this)); - - auto menu = Menu::create(item, NULL); - this->addChild(menu); - menu->setPosition(Point(VisibleRect::right().x-100, VisibleRect::top().y-60)); - - auto sp = Sprite::create(); - auto body = PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size); - sp->setPhysicsBody(body); - this->addChild(sp); - sp->setPosition(VisibleRect::center()); - - auto parent = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100); - _spriteTexture = parent->getTexture(); - - addNewSpriteAtPosition(VisibleRect::center()); - - createResetButton(); + addGrossiniAtPosition(VisibleRect::center()); #else auto label = LabelTTF::create("Should define CC_USE_BOX2D or CC_USE_CHIPMUNK\n to run this test case", @@ -47,41 +212,12 @@ PhysicsTestLayer::PhysicsTestLayer() #endif } -void PhysicsTestLayer::toggleDebugCallback(Object* sender) +std::string PhysicsDemoClickAdd::subtitle() { -#ifdef CC_USE_PHYSICS - if (_scene != nullptr) - { - _scene->getPhysicsWorld()->setDebugDraw(!_scene->getPhysicsWorld()->isDebugDraw()); - } -#endif + return "multi touch to add grossini"; } -PhysicsTestLayer::~PhysicsTestLayer() -{ -} - -void PhysicsTestLayer::createResetButton() -{ - auto reset = MenuItemImage::create("Images/r1.png", "Images/r2.png", [](Object *sender) { - auto s = new PhysicsTestScene(); - s->initTest(); - auto child = new PhysicsTestLayer(); - child->setScene(s); - s->addChild(child); - child->release(); - Director::getInstance()->replaceScene(s); - s->release(); - }); - - auto menu = Menu::create(reset, NULL); - - menu->setPosition(Point(VisibleRect::bottom().x, VisibleRect::bottom().y + 30)); - this->addChild(menu, -1); - -} - -void PhysicsTestLayer::onTouchesEnded(const std::vector& touches, Event* event) +void PhysicsDemoClickAdd::onTouchesEnded(const std::vector& touches, Event* event) { //Add a new body/atlas sprite at the touched location @@ -89,12 +225,11 @@ void PhysicsTestLayer::onTouchesEnded(const std::vector& touches, Event* { auto location = touch->getLocation(); - addNewSpriteAtPosition( location ); + addGrossiniAtPosition( location ); } } - -void PhysicsTestLayer::onAcceleration(Acceleration* acc, Event* event) +void PhysicsDemoClickAdd::onAcceleration(Acceleration* acc, Event* event) { #ifdef CC_USE_PHYSICS static float prevX=0, prevY=0; @@ -117,48 +252,169 @@ void PhysicsTestLayer::onAcceleration(Acceleration* acc, Event* event) #endif } -void PhysicsTestLayer::addNewSpriteAtPosition(Point p) +namespace { -#ifdef CC_USE_PHYSICS - CCLOG("Add sprite %0.2f x %02.f",p.x,p.y); - - int posx, posy; - - posx = CCRANDOM_0_1() * 200.0f; - posy = CCRANDOM_0_1() * 200.0f; - - posx = (posx % 4) * 85; - posy = (posy % 3) * 121; - - auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121)); - auto body = PhysicsBody::createBox(Size(48, 108)); - sp->setPhysicsBody(body); - sp->setPosition(p); - this->addChild(sp); -#endif -} - -bool PhysicsTestScene::initTest() -{ -#ifdef CC_USE_PHYSICS - if (TestScene::initWithPhysics()) + static const int logo_width = 188; + static const int logo_height = 35; + static const int logo_row_length = 24; + static const char logo_image[] = { - this->getPhysicsWorld()->setDebugDraw(true); - return true; - } -#else - return TestScene::init(); -#endif + 15,-16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-64,15,63,-32,-2,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,31,-64,15,127,-125,-1,-128,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,127,-64,15,127,15,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-2, + 31,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,0,-4,63,-1,-32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-8,127,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,-1,-64,0,-8,-15,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-31,-1,-64,15,-8,-32, + -1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-15,-1,-64,9,-15,-32,-1,-32,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,31,-15,-1,-64,0,-15,-32,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,63,-7,-1,-64,9,-29,-32,127,-61,-16,63,15,-61,-1,-8,31,-16,15,-8,126,7,-31, + -8,31,-65,-7,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -4,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -2,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -2,63,-33,-1,-1,-32,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-33,-1,-1,-16,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-49,-1,-1,-8,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-49,-1,-1,-4,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-57,-1,-1,-2,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-1,-57,-1,-1,-1,9,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-119,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-55,-49,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-63,-1,-1,-1,-23,-49,-32,127,-57,-1,-1,-97,-25,-1,-1,63,-1,-1,-4,-1,15,-13, + -1,-1,-63,-1,-1,-1,-16,-49,-32,-1,-25,-1,-1,-97,-25,-1,-1,63,-33,-5,-4,-1,15, + -13,-1,-1,-64,-1,-9,-1,-7,-49,-32,-1,-25,-8,127,-97,-25,-1,-1,63,-33,-5,-4,-1, + 15,-13,-1,-1,-64,-1,-13,-1,-32,-49,-32,-1,-25,-8,127,-97,-25,-1,-2,63,-49,-13, + -4,-1,15,-13,-1,-1,-64,127,-7,-1,-119,-17,-15,-1,-25,-8,127,-97,-25,-1,-2,63, + -49,-13,-4,-1,15,-13,-3,-1,-64,127,-8,-2,15,-17,-1,-1,-25,-8,127,-97,-25,-1, + -8,63,-49,-13,-4,-1,15,-13,-3,-1,-64,63,-4,120,0,-17,-1,-1,-25,-8,127,-97,-25, + -8,0,63,-57,-29,-4,-1,15,-13,-4,-1,-64,63,-4,0,15,-17,-1,-1,-25,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,-1,-64,31,-2,0,0,103,-1,-1,-57,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,127,-64,31,-2,0,15,103,-1,-1,-57,-8,127, + -97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,127,-64,15,-8,0,0,55,-1,-1,-121,-8, + 127,-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,63,-64,15,-32,0,0,23,-1,-2,3,-16, + 63,15,-61,-16,0,31,-127,-127,-8,31,-1,-127,-8,31,-128,7,-128,0,0}; - return false; + static inline int get_pixel(int x, int y) + { + return (logo_image[(x>>3) + y*logo_row_length]>>(~x&0x7)) & 1; + } + + static inline float frand(void) + { + return rand()/RAND_MAX; + } } -void PhysicsTestScene::runThisTest() +Node* PhysicsDemoLogoSmash::makeBall(float x, float y) { - auto layer = new PhysicsTestLayer(); - layer->setScene(this); - addChild(layer); - layer->release(); + auto ball = Sprite::createWithTexture(_ball->getTexture()); + ball->setScale(0.1); - Director::getInstance()->replaceScene(this); + auto body = PhysicsBody::createCircle(0.95, PhysicsMaterial(1, 0, 0)); + body->setMass(1.0); + body->setAngularDamping(PHYSICS_INFINITY); + + //body->setDynamic(false); + ball->setPhysicsBody(body); + + ball->setPosition(Point(x, y)); + + return ball; } + +void PhysicsDemoLogoSmash::onEnter() +{ + PhysicsDemo::onEnter(); + + _scene->getPhysicsWorld()->setGravity(Point(0, 0)); + + _ball = SpriteBatchNode::create("Images/ball.png", sizeof(logo_image)/sizeof(logo_image[0])); + addChild(_ball); + for (int y = 0; y < logo_height; ++y) + { + for (int x = 0; x < logo_width; ++x) + { + if (get_pixel(x, y)) + { + 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)); + } + } + } + + + 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); + + bullet->setPosition(Point(-1000, VisibleRect::getVisibleRect().size.height/2)); + + _ball->addChild(bullet); +} + +std::string PhysicsDemoLogoSmash::title() +{ + return "Logo Smash"; +} + +void PhysicsDemoPyramidStack::onEnter() +{ + PhysicsDemo::onEnter(); + + auto node = Node::create(); + node->setPhysicsBody(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Point(0, 50), VisibleRect::rightBottom() + Point(0, 50))); + this->addChild(node); + + auto ball = Sprite::create("Images/ball.png"); + ball->setScale(1); + ball->setPhysicsBody(PhysicsBody::createCircle(10)); + ball->setPosition(VisibleRect::bottom() + Point(0, 60)); + this->addChild(ball); + + for(int i=0; i<14; i++) + { + for(int j=0; j<=i; j++) + { + addGrossiniAtPosition(VisibleRect::bottom() + Point((i/2 - j) * 11, (14 - i) * 23 + 100), 0.2); + } + } +} +std::string PhysicsDemoPyramidStack::title() +{ + return "Pyramid Stack"; +} + + +void PhysicsDemoPlink::onEnter() +{ + PhysicsDemo::onEnter(); + + auto node = Node::create(); + auto body = PhysicsBody::create(); + body->setDynamic(false); + node->setPhysicsBody(body); + + Point tris[] = { Point(-15, -15), Point(0, 10), Point(15, -15) }; + + auto rect = VisibleRect::getVisibleRect(); + for (int i = 0; i < 9; ++i) + { + 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))); + } + } + + addChild(node); + +} + +std::string PhysicsDemoPlink::title() +{ + return "Plink"; +} \ 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 3c95ed90c8..34f8053b37 100644 --- a/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h +++ b/samples/Cpp/TestCpp/Classes/PhysicsTest/PhysicsTest.h @@ -3,30 +3,79 @@ #include "cocos2d.h" #include "../testBasic.h" +#include "../BaseTest.h" -class PhysicsTestLayer : public Layer -{ - Texture2D* _spriteTexture; // weak ref - Scene* _scene; - -public: - PhysicsTestLayer(); - ~PhysicsTestLayer(); - - void createResetButton(); - - inline void setScene(Scene* scene) { _scene = scene; } - void toggleDebugCallback(Object* sender); - void addNewSpriteAtPosition(Point p); - virtual void onTouchesEnded(const std::vector& touches, Event* event) override; - virtual void onAcceleration(Acceleration* acc, Event* event) override; -} ; class PhysicsTestScene : public TestScene { public: virtual bool initTest() override; virtual void runThisTest(); + + void toggleDebug(); + +private: + static bool _debugDraw; +}; + +class PhysicsDemo : public BaseTest +{ +protected: + PhysicsTestScene* _scene; + +public: + PhysicsDemo(); + virtual ~PhysicsDemo(); + + virtual void onEnter() override; + virtual std::string title() override; + virtual std::string subtitle() override; + + void restartCallback(Object* sender); + void nextCallback(Object* sender); + void backCallback(Object* sender); + void toggleDebugCallback(Object* sender); + + void addGrossiniAtPosition(Point p, float scale = 1.0); + +private: + Texture2D* _spriteTexture; // weak ref +}; + +class PhysicsDemoClickAdd : public PhysicsDemo +{ +public: + void onEnter() override; + std::string subtitle() override; + + void onTouchesEnded(const std::vector& touches, Event* event) override; + void onAcceleration(Acceleration* acc, Event* event) override; +}; + +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 +{ +public: + void onEnter() override; + std::string title() override; +}; + +class PhysicsDemoPlink : public PhysicsDemo +{ +public: + void onEnter() override; + std::string title() override; }; #endif