From 91126341bd05f1aed584edae3fea0ef523816578 Mon Sep 17 00:00:00 2001 From: boyu0 Date: Fri, 27 Jun 2014 17:30:21 +0800 Subject: [PATCH 1/2] fix transform for physics. --- cocos/2d/CCActionInterval.cpp | 4 +- cocos/2d/CCNode.cpp | 116 +++++++----- cocos/2d/CCNode.h | 4 + cocos/physics/CCPhysicsBody.cpp | 39 +++- cocos/physics/CCPhysicsBody.h | 4 + cocos/physics/CCPhysicsShape.cpp | 309 ++++++++++++++++++++++++------- cocos/physics/CCPhysicsShape.h | 110 ++++++----- 7 files changed, 414 insertions(+), 172 deletions(-) diff --git a/cocos/2d/CCActionInterval.cpp b/cocos/2d/CCActionInterval.cpp index 9caf34d096..0c2fa35146 100644 --- a/cocos/2d/CCActionInterval.cpp +++ b/cocos/2d/CCActionInterval.cpp @@ -829,7 +829,7 @@ void RotateTo::update(float time) if (_target) { #if CC_USE_PHYSICS - if (_target->getPhysicsBody() != nullptr && _startAngleX == _startAngleY && _diffAngleX == _diffAngleY) + if (_startAngleX == _startAngleY && _diffAngleX == _diffAngleY) { _target->setRotation(_startAngleX + _diffAngleX * time); } @@ -971,7 +971,7 @@ void RotateBy::update(float time) else { #if CC_USE_PHYSICS - if (_target->getPhysicsBody() != nullptr && _startAngleZ_X == _startAngleZ_Y && _angleZ_X == _angleZ_Y) + if (_startAngleZ_X == _startAngleZ_Y && _angleZ_X == _angleZ_Y) { _target->setRotation(_startAngleZ_X + _angleZ_X * time); } diff --git a/cocos/2d/CCNode.cpp b/cocos/2d/CCNode.cpp index fc9d7a5171..18c71c7721 100644 --- a/cocos/2d/CCNode.cpp +++ b/cocos/2d/CCNode.cpp @@ -116,6 +116,8 @@ Node::Node(void) , _componentContainer(nullptr) #if CC_USE_PHYSICS , _physicsBody(nullptr) +, _physicsScaleStartX(1.0f) +, _physicsScaleStartY(1.0f) #endif , _displayedOpacity(255) , _realOpacity(255) @@ -283,10 +285,9 @@ void Node::setRotation(float rotation) _transformUpdated = _transformDirty = _inverseDirty = true; #if CC_USE_PHYSICS - if (_physicsBody && !_physicsBody->_rotationResetTag) + if (!_physicsBody || !_physicsBody->_rotationResetTag) { - Scene* scene = _physicsBody->getWorld() != nullptr ? &_physicsBody->getWorld()->getScene() : nullptr; - updatePhysicsBodyRotation(scene); + updatePhysicsBodyRotation(getScene()); } #endif } @@ -377,15 +378,12 @@ void Node::setScale(float scale) if (_scaleX == scale) return; -#if CC_USE_PHYSICS - if (_physicsBody != nullptr) - { - CCLOG("Node WARNING: PhysicsBody doesn't support setScale"); - } -#endif - _scaleX = _scaleY = _scaleZ = scale; _transformUpdated = _transformDirty = _inverseDirty = true; + +#if CC_USE_PHYSICS + updatePhysicsBodyTransform(getScene()); +#endif } /// scaleX getter @@ -400,16 +398,13 @@ void Node::setScale(float scaleX,float scaleY) if (_scaleX == scaleX && _scaleY == scaleY) return; -#if CC_USE_PHYSICS - if (_physicsBody != nullptr) - { - CCLOG("Node WARNING: PhysicsBody doesn't support setScale"); - } -#endif - _scaleX = scaleX; _scaleY = scaleY; _transformUpdated = _transformDirty = _inverseDirty = true; + +#if CC_USE_PHYSICS + updatePhysicsBodyTransform(getScene()); +#endif } /// scaleX setter @@ -418,15 +413,12 @@ void Node::setScaleX(float scaleX) if (_scaleX == scaleX) return; -#if CC_USE_PHYSICS - if (_physicsBody != nullptr) - { - CCLOG("Node WARNING: PhysicsBody doesn't support setScaleX"); - } -#endif - _scaleX = scaleX; _transformUpdated = _transformDirty = _inverseDirty = true; + +#if CC_USE_PHYSICS + updatePhysicsBodyTransform(getScene()); +#endif } /// scaleY getter @@ -464,15 +456,12 @@ void Node::setScaleY(float scaleY) if (_scaleY == scaleY) return; -#if CC_USE_PHYSICS - if (_physicsBody != nullptr) - { - CCLOG("Node WARNING: PhysicsBody doesn't support setScaleY"); - } -#endif - _scaleY = scaleY; _transformUpdated = _transformDirty = _inverseDirty = true; + +#if CC_USE_PHYSICS + updatePhysicsBodyTransform(getScene()); +#endif } @@ -493,10 +482,9 @@ void Node::setPosition(const Vec2& position) _usingNormalizedPosition = false; #if CC_USE_PHYSICS - if (_physicsBody != nullptr && !_physicsBody->_positionResetTag) + if (!_physicsBody || !_physicsBody->_positionResetTag) { - Scene* scene = _physicsBody->getWorld() != nullptr ? &_physicsBody->getWorld()->getScene() : nullptr; - updatePhysicsBodyPosition(scene); + updatePhysicsBodyPosition(getScene()); } #endif } @@ -1004,14 +992,11 @@ void Node::addChild(Node *child, int zOrder, int tag) #if CC_USE_PHYSICS // Recursive add children with which have physics body. - for (Node* node = this; node != nullptr; node = node->getParent()) + Scene* scene = this->getScene(); + if (scene != nullptr && scene->getPhysicsWorld() != nullptr) { - Scene* scene = dynamic_cast(node); - if (scene != nullptr && scene->getPhysicsWorld() != nullptr) - { - scene->addChildToPhysicsWorld(child); - break; - } + child->updatePhysicsBodyTransform(scene); + scene->addChildToPhysicsWorld(child); } #endif @@ -1838,6 +1823,12 @@ void Node::removeAllComponents() } #if CC_USE_PHYSICS +void Node::updatePhysicsBodyTransform(Scene* scene) +{ + updatePhysicsBodyScale(scene); + updatePhysicsBodyPosition(scene); + updatePhysicsBodyRotation(scene); +} void Node::updatePhysicsBodyPosition(Scene* scene) { @@ -1853,6 +1844,11 @@ void Node::updatePhysicsBodyPosition(Scene* scene) _physicsBody->setPosition(getPosition()); } } + + for (Node* child : _children) + { + child->updatePhysicsBodyPosition(scene); + } } void Node::updatePhysicsBodyRotation(Scene* scene) @@ -1873,6 +1869,39 @@ void Node::updatePhysicsBodyRotation(Scene* scene) _physicsBody->setRotation(_rotationZ_X); } } + + for (auto child : _children) + { + child->updatePhysicsBodyRotation(scene); + child->updatePhysicsBodyPosition(scene); + } +} + +void Node::updatePhysicsBodyScale(Scene* scene) +{ + if (_physicsBody != nullptr) + { + if (scene != nullptr && scene->getPhysicsWorld() != nullptr) + { + float scaleX = _scaleX / _physicsScaleStartX; + float scaleY = _scaleY / _physicsScaleStartY; + for (Node* parent = _parent; parent != scene; parent = parent->getParent()) + { + scaleX *= parent->getScaleX(); + scaleY *= parent->getScaleY(); + } + _physicsBody->setScale(scaleX, scaleY); + } + else + { + _physicsBody->setScale(_scaleX / _physicsScaleStartX, _scaleY / _physicsScaleStartY); + } + } + + for (auto child : _children) + { + child->updatePhysicsBodyScale(scene); + } } void Node::setPhysicsBody(PhysicsBody* body) @@ -1915,6 +1944,8 @@ void Node::setPhysicsBody(PhysicsBody* body) } _physicsBody = body; + _physicsScaleStartX = _scaleX; + _physicsScaleStartY = _scaleY; if (body != nullptr) { @@ -1935,8 +1966,7 @@ void Node::setPhysicsBody(PhysicsBody* body) scene->getPhysicsWorld()->addBody(body); } - updatePhysicsBodyPosition(scene); - updatePhysicsBodyRotation(scene); + updatePhysicsBodyTransform(scene); } } diff --git a/cocos/2d/CCNode.h b/cocos/2d/CCNode.h index c3b9b42e93..7703b1f2e7 100644 --- a/cocos/2d/CCNode.h +++ b/cocos/2d/CCNode.h @@ -1472,8 +1472,10 @@ protected: bool doEnumerateRecursive(const Node* node, const std::string &name, std::function callback) const; #if CC_USE_PHYSICS + void updatePhysicsBodyTransform(Scene* layer); virtual void updatePhysicsBodyPosition(Scene* layer); virtual void updatePhysicsBodyRotation(Scene* layer); + virtual void updatePhysicsBodyScale(Scene* scene); #endif // CC_USE_PHYSICS float _rotationX; ///< rotation on the X-axis @@ -1556,6 +1558,8 @@ protected: #if CC_USE_PHYSICS PhysicsBody* _physicsBody; ///< the physicsBody the node have + float _physicsScaleStartX; ///< the scale x value when setPhysicsBody + float _physicsScaleStartY; ///< the scale y value when setPhysicsBody #endif // opacity controls diff --git a/cocos/physics/CCPhysicsBody.cpp b/cocos/physics/CCPhysicsBody.cpp index 477d177a78..bc38e34e32 100644 --- a/cocos/physics/CCPhysicsBody.cpp +++ b/cocos/physics/CCPhysicsBody.cpp @@ -355,6 +355,38 @@ void PhysicsBody::setRotation(float rotation) cpBodySetAngle(_info->getBody(), -PhysicsHelper::float2cpfloat((rotation + _rotationOffset) * (M_PI / 180.0f))); } +void PhysicsBody::setScale(float scale) +{ + for (auto shape : _shapes) + { + shape->setScale(scale); + } +} + +void PhysicsBody::setScale(float scaleX, float scaleY) +{ + for (auto shape : _shapes) + { + shape->setScale(scaleX, scaleY); + } +} + +void PhysicsBody::setScaleX(float scaleX) +{ + for (auto shape : _shapes) + { + shape->setScaleX(scaleX); + } +} + +void PhysicsBody::setScaleY(float scaleY) +{ + for (auto shape : _shapes) + { + shape->setScaleY(scaleY); + } +} + Vec2 PhysicsBody::getPosition() const { cpVect vec = cpBodyGetPos(_info->getBody()); @@ -763,8 +795,13 @@ void PhysicsBody::update(float delta) { if (_node != nullptr) { + for (auto shape : _shapes) + { + shape->update(delta); + } + Node* parent = _node->getParent(); - Scene* scene = &_world->getScene(); + Node* scene = &_world->getScene(); Vec2 position = parent != scene ? parent->convertToNodeSpace(scene->convertToWorldSpace(getPosition())) : getPosition(); float rotation = getRotation(); diff --git a/cocos/physics/CCPhysicsBody.h b/cocos/physics/CCPhysicsBody.h index 148c103b81..a9de180e0d 100644 --- a/cocos/physics/CCPhysicsBody.h +++ b/cocos/physics/CCPhysicsBody.h @@ -303,6 +303,10 @@ protected: virtual void setPosition(Vec2 position); virtual void setRotation(float rotation); + virtual void setScale(float scale); + virtual void setScale(float scaleX, float scaleY); + virtual void setScaleX(float scaleX); + virtual void setScaleY(float scaleY); void update(float delta); diff --git a/cocos/physics/CCPhysicsShape.cpp b/cocos/physics/CCPhysicsShape.cpp index d4e74c92e7..0fcfcfd820 100644 --- a/cocos/physics/CCPhysicsShape.cpp +++ b/cocos/physics/CCPhysicsShape.cpp @@ -28,6 +28,7 @@ #include #include "chipmunk.h" +#include "chipmunk_unsafe.h" #include "physics/CCPhysicsBody.h" #include "physics/CCPhysicsWorld.h" @@ -43,9 +44,14 @@ PhysicsShape::PhysicsShape() : _body(nullptr) , _info(nullptr) , _type(Type::UNKNOWN) -, _area(0) -, _mass(0) -, _moment(0) +, _area(0.0f) +, _mass(0.0f) +, _moment(0.0f) +, _scaleX(1.0f) +, _scaleY(1.0f) +, _newScaleX(1.0f) +, _newScaleY(1.0f) +, _dirty(false) , _tag(0) , _categoryBitmask(UINT_MAX) , _collisionBitmask(UINT_MAX) @@ -120,6 +126,52 @@ PhysicsBodyInfo* PhysicsShape::bodyInfo() const } } +void PhysicsShape::setScale(float scale) +{ + setScaleX(scale); + setScaleY(scale); +} + +void PhysicsShape::setScale(float scaleX, float scaleY) +{ + setScaleX(scaleX); + setScaleY(scaleY); +} + +void PhysicsShape::setScaleX(float scaleX) +{ + if (_scaleX == scaleX) + { + return; + } + + _newScaleX = scaleX; + _dirty = true; +} + +void PhysicsShape::setScaleY(float scaleY) +{ + if (_scaleY == scaleY) + { + return; + } + + _newScaleY = scaleY; + _dirty = true; +} + +void PhysicsShape::update(float delta) +{ + CC_UNUSED_PARAM(delta); + + if (_dirty) + { + _scaleX = _newScaleX; + _scaleY = _newScaleY; + _dirty = false; + } +} + PhysicsShapeCircle::PhysicsShapeCircle() { @@ -355,6 +407,66 @@ Vec2 PhysicsShapeCircle::getOffset() return PhysicsHelper::cpv2point(cpCircleShapeGetOffset(_info->getShapes().front())); } +void PhysicsShapeCircle::setScale(float scale) +{ + if (_scaleX == scale) + { + return; + } + + _newScaleX = _newScaleY = scale; + _dirty = true; +} + +void PhysicsShapeCircle::setScale(float scaleX, float scaleY) +{ + if (scaleX != scaleY) + { + CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScale with different x and y"); + } + + if (_scaleX == scaleX) + { + return; + } + + _newScaleX = _newScaleY = scaleX; + _dirty = true; +} + +void PhysicsShapeCircle::setScaleX(float scale) +{ + CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScaleX"); + + setScale(scale); +} + +void PhysicsShapeCircle::setScaleY(float scale) +{ + CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScaleY"); + + setScale(scale); +} + +void PhysicsShapeCircle::update(float delta) +{ + + if (_dirty) + { + cpFloat factor = PhysicsHelper::float2cpfloat( _newScaleX / _scaleX ); + + cpShape* shape = _info->getShapes().front(); + cpVect v = cpCircleShapeGetOffset(shape); + v = cpvmult(v, PhysicsHelper::float2cpfloat(factor)); + ((cpCircleShape*)shape)->c = v; + + cpCircleShapeSetRadius(shape, cpCircleShapeGetRadius(shape) * factor); + } + + PhysicsShape::update(delta); + +} + // PhysicsShapeEdgeSegment PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(const Vec2& a, const Vec2& b, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/) { @@ -386,7 +498,6 @@ bool PhysicsShapeEdgeSegment::init(const Vec2& a, const Vec2& b, const PhysicsMa _mass = PHYSICS_INFINITY; _moment = PHYSICS_INFINITY; - _center = a.getMidpoint(b); setMaterial(material); @@ -409,7 +520,29 @@ Vec2 PhysicsShapeEdgeSegment::getPointB() const Vec2 PhysicsShapeEdgeSegment::getCenter() { - return _center; + Vec2 a = PhysicsHelper::cpv2point(cpSegmentShapeGetA(_info->getShapes().front())); + Vec2 b = PhysicsHelper::cpv2point(cpSegmentShapeGetB(_info->getShapes().front())); + return ( a + b ) / 2; +} + +void PhysicsShapeEdgeSegment::update(float delta) +{ + if (_dirty) + { + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + cpShape* shape = _info->getShapes().front(); + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); + } + + PhysicsShape::update(delta); } // PhysicsShapeBox @@ -444,7 +577,6 @@ bool PhysicsShapeBox::init(const Size& size, const PhysicsMaterial& material/* = _info->add(shape); - _offset = offset; _area = calculateArea(); _mass = material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : material.density * _area; _moment = calculateDefaultMoment(); @@ -457,50 +589,6 @@ bool PhysicsShapeBox::init(const Size& size, const PhysicsMaterial& material/* = return false; } -float PhysicsShapeBox::calculateArea(const Size& size) -{ - cpVect wh = PhysicsHelper::size2cpv(size); - cpVect vec[4] = - { - {-wh.x/2.0f, -wh.y/2.0f}, {-wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, -wh.y/2.0f} - }; - return PhysicsHelper::cpfloat2float(cpAreaForPoly(4, vec)); -} - -float PhysicsShapeBox::calculateMoment(float mass, const Size& size, const Vec2& offset) -{ - cpVect wh = PhysicsHelper::size2cpv(size); - cpVect vec[4] = - { - {-wh.x/2.0f, -wh.y/2.0f}, {-wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, -wh.y/2.0f} - }; - - return mass == PHYSICS_INFINITY ? PHYSICS_INFINITY - : PhysicsHelper::cpfloat2float(cpMomentForPoly(PhysicsHelper::float2cpfloat(mass), - 4, - vec, - PhysicsHelper::point2cpv(offset))); -} - -float PhysicsShapeBox::calculateArea() -{ - cpShape* shape = _info->getShapes().front(); - return PhysicsHelper::cpfloat2float(cpAreaForPoly(((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts)); -} - -float PhysicsShapeBox::calculateDefaultMoment() -{ - cpShape* shape = _info->getShapes().front(); - return _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY - : PhysicsHelper::cpfloat2float(cpMomentForPoly(_mass, ((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts, cpvzero)); -} - -void PhysicsShapeBox::getPoints(Vec2* points) const -{ - cpShape* shape = _info->getShapes().front(); - PhysicsHelper::cpvs2points(((cpPolyShape*)shape)->verts, points, ((cpPolyShape*)shape)->numVerts); -} - Size PhysicsShapeBox::getSize() const { cpShape* shape = _info->getShapes().front(); @@ -540,7 +628,6 @@ bool PhysicsShapePolygon::init(const Vec2* points, int count, const PhysicsMater _area = calculateArea(); _mass = material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : material.density * _area; _moment = calculateDefaultMoment(); - _center = PhysicsHelper::cpv2point(cpCentroidForPoly(((cpPolyShape*)shape)->numVerts, ((cpPolyShape*)shape)->verts)); setMaterial(material); @@ -602,7 +689,37 @@ int PhysicsShapePolygon::getPointsCount() const Vec2 PhysicsShapePolygon::getCenter() { - return _center; + return PhysicsHelper::cpv2point(cpCentroidForPoly(((cpPolyShape*)_info->getShapes().front())->numVerts, ((cpPolyShape*)_info->getShapes().front())->verts)); +} + +void PhysicsShapePolygon::update(float delta) +{ + if (_dirty) + { + cpFloat factorX = PhysicsHelper::float2cpfloat( _newScaleX / _scaleX ); + cpFloat factorY = PhysicsHelper::float2cpfloat( _newScaleY / _scaleY ); + + cpShape* shape = _info->getShapes().front(); + int count = cpPolyShapeGetNumVerts(shape); + cpVect* vects = ((cpPolyShape*)shape)->verts; + cpSplittingPlane* planes = ((cpPolyShape*)shape)->planes; + + for (int i = 0; i < count ; ++i) + { + vects[i].x *= factorX; + vects[i].y *= factorY; + } + + for (int i = 0; i < count; ++i) + { + cpVect n = cpvnormalize(cpvperp(cpvsub(vects[i], vects[(i + 1) % count]))); + + planes[i].n = n; + planes[i].d = cpvdot(n, vects[i]); + } + } + + PhysicsShape::update(delta); } // PhysicsShapeEdgeBox @@ -641,7 +758,6 @@ bool PhysicsShapeEdgeBox::init(const Size& size, const PhysicsMaterial& material } CC_BREAK_IF(i < 4); - _offset = offset; _mass = PHYSICS_INFINITY; _moment = PHYSICS_INFINITY; @@ -653,15 +769,6 @@ bool PhysicsShapeEdgeBox::init(const Size& size, const PhysicsMaterial& material return false; } -void PhysicsShapeEdgeBox::getPoints(cocos2d::Vec2 *outPoints) const -{ - int i = 0; - for(auto shape : _info->getShapes()) - { - outPoints[i++] = PhysicsHelper::cpv2point(((cpSegmentShape*)shape)->a); - } -} - // PhysicsShapeEdgeBox PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/) { @@ -685,7 +792,6 @@ bool PhysicsShapeEdgePolygon::init(const Vec2* points, int count, const PhysicsM vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); - _center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, vec)); int i = 0; for (; i < count; ++i) @@ -716,7 +822,18 @@ bool PhysicsShapeEdgePolygon::init(const Vec2* points, int count, const PhysicsM Vec2 PhysicsShapeEdgePolygon::getCenter() { - return _center; + int count = (int)_info->getShapes().size(); + cpVect* points = new cpVect[count]; + int i = 0; + for(auto shape : _info->getShapes()) + { + points[i++] = ((cpSegmentShape*)shape)->a; + } + + Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, points)); + delete[] points; + + return center; } void PhysicsShapeEdgePolygon::getPoints(cocos2d::Vec2 *outPoints) const @@ -730,7 +847,7 @@ void PhysicsShapeEdgePolygon::getPoints(cocos2d::Vec2 *outPoints) const int PhysicsShapeEdgePolygon::getPointsCount() const { - return static_cast(_info->getShapes().size() + 1); + return static_cast(_info->getShapes().size()); } // PhysicsShapeEdgeChain @@ -747,6 +864,28 @@ PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(const Vec2* points, int cou return nullptr; } +void PhysicsShapeEdgePolygon::update(float delta) +{ + if (_dirty) + { + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + for(auto shape : _info->getShapes()) + { + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); + } + } + + PhysicsShape::update(delta); +} + bool PhysicsShapeEdgeChain::init(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/) { cpVect* vec = nullptr; @@ -756,7 +895,6 @@ bool PhysicsShapeEdgeChain::init(const Vec2* points, int count, const PhysicsMat vec = new cpVect[count]; PhysicsHelper::points2cpvs(points, vec, count); - _center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, vec)); int i = 0; for (; i < count - 1; ++i) @@ -786,7 +924,20 @@ bool PhysicsShapeEdgeChain::init(const Vec2* points, int count, const PhysicsMat Vec2 PhysicsShapeEdgeChain::getCenter() { - return _center; + int count = (int)_info->getShapes().size() + 1; + cpVect* points = new cpVect[count]; + int i = 0; + for(auto shape : _info->getShapes()) + { + points[i++] = ((cpSegmentShape*)shape)->a; + } + + points[i++] = ((cpSegmentShape*)_info->getShapes().back())->b; + + Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, points)); + delete[] points; + + return center; } void PhysicsShapeEdgeChain::getPoints(Vec2* outPoints) const @@ -797,7 +948,7 @@ void PhysicsShapeEdgeChain::getPoints(Vec2* outPoints) const outPoints[i++] = PhysicsHelper::cpv2point(((cpSegmentShape*)shape)->a); } - outPoints[i++] = PhysicsHelper::cpv2point(((cpSegmentShape*)_info->getShapes().back())->a); + outPoints[i++] = PhysicsHelper::cpv2point(((cpSegmentShape*)_info->getShapes().back())->b); } int PhysicsShapeEdgeChain::getPointsCount() const @@ -805,6 +956,28 @@ int PhysicsShapeEdgeChain::getPointsCount() const return static_cast(_info->getShapes().size() + 1); } +void PhysicsShapeEdgeChain::update(float delta) +{ + if (_dirty) + { + cpFloat factorX = PhysicsHelper::float2cpfloat(_newScaleX / _scaleX); + cpFloat factorY = PhysicsHelper::float2cpfloat(_newScaleY / _scaleY); + + for(auto shape : _info->getShapes()) + { + cpVect a = cpSegmentShapeGetA(shape); + a.x *= factorX; + a.y *= factorY; + cpVect b = cpSegmentShapeGetB(shape); + b.x *= factorX; + b.y *= factorY; + cpSegmentShapeSetEndpoints(shape, a, b); + } + } + + PhysicsShape::update(delta); +} + void PhysicsShape::setGroup(int group) { if (group < 0) diff --git a/cocos/physics/CCPhysicsShape.h b/cocos/physics/CCPhysicsShape.h index e677692fc0..c8921b0430 100644 --- a/cocos/physics/CCPhysicsShape.h +++ b/cocos/physics/CCPhysicsShape.h @@ -156,6 +156,12 @@ protected: /** calculate the area of this shape */ virtual float calculateArea() { return 0.0f; } + virtual void setScale(float scale); + virtual void setScale(float scaleX, float scaleY); + virtual void setScaleX(float scaleX); + virtual void setScaleY(float scaleY); + virtual void update(float delta); + protected: PhysicsShape(); virtual ~PhysicsShape() = 0; @@ -167,6 +173,11 @@ protected: float _area; float _mass; float _moment; + float _scaleX; + float _scaleY; + float _newScaleX; + float _newScaleY; + bool _dirty; PhysicsMaterial _material; int _tag; int _categoryBitmask; @@ -192,42 +203,21 @@ public: float getRadius() const; virtual Vec2 getOffset() override; + protected: bool init(float radius, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); virtual float calculateArea() override; + virtual void setScale(float scale) override; + virtual void setScale(float scaleX, float scaleY) override; + virtual void setScaleX(float scale) override; + virtual void setScaleY(float scale) override; + virtual void update(float delta) override; protected: PhysicsShapeCircle(); virtual ~PhysicsShapeCircle(); }; -/** A box shape */ -class PhysicsShapeBox : public PhysicsShape -{ -public: - static PhysicsShapeBox* create(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); - static float calculateArea(const Size& size); - static float calculateMoment(float mass, const Size& size, const Vec2& offset = Vec2::ZERO); - - virtual float calculateDefaultMoment() override; - - void getPoints(Vec2* outPoints) const; - int getPointsCount() const { return 4; } - Size getSize() const; - virtual Vec2 getOffset() override { return _offset; } - -protected: - bool init(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); - virtual float calculateArea() override; - -protected: - PhysicsShapeBox(); - virtual ~PhysicsShapeBox(); - -protected: - Vec2 _offset; -}; - /** A polygon shape */ class PhysicsShapePolygon : public PhysicsShape { @@ -245,13 +235,28 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); float calculateArea() override; + virtual void update(float delta) override; protected: PhysicsShapePolygon(); virtual ~PhysicsShapePolygon(); +}; + +/** A box shape */ +class PhysicsShapeBox : public PhysicsShapePolygon +{ +public: + static PhysicsShapeBox* create(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); + + Size getSize() const; + virtual Vec2 getOffset() override { return getCenter(); } protected: - Vec2 _center; + bool init(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, const Vec2& offset = Vec2::ZERO); + +protected: + PhysicsShapeBox(); + virtual ~PhysicsShapeBox(); }; /** A segment shape */ @@ -266,36 +271,12 @@ public: protected: bool init(const Vec2& a, const Vec2& b, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); + virtual void update(float delta) override; protected: PhysicsShapeEdgeSegment(); virtual ~PhysicsShapeEdgeSegment(); -protected: - Vec2 _center; - - friend class PhysicsBody; -}; - -/** An edge box shape */ -class PhysicsShapeEdgeBox : public PhysicsShape -{ -public: - static PhysicsShapeEdgeBox* create(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 0, const Vec2& offset = Vec2::ZERO); - virtual Vec2 getOffset() override { return _offset; } - void getPoints(Vec2* outPoints) const; - int getPointsCount() const { return 4; } - -protected: - bool init(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1, const Vec2& offset = Vec2::ZERO); - -protected: - PhysicsShapeEdgeBox(); - virtual ~PhysicsShapeEdgeBox(); - -protected: - Vec2 _offset; - friend class PhysicsBody; }; @@ -310,15 +291,30 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); + virtual void update(float delta) override; protected: PhysicsShapeEdgePolygon(); virtual ~PhysicsShapeEdgePolygon(); friend class PhysicsBody; +}; + +/** An edge box shape */ +class PhysicsShapeEdgeBox : public PhysicsShapeEdgePolygon +{ +public: + static PhysicsShapeEdgeBox* create(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 0, const Vec2& offset = Vec2::ZERO); + virtual Vec2 getOffset() override { return getCenter(); } protected: - Vec2 _center; + bool init(const Size& size, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1, const Vec2& offset = Vec2::ZERO); + +protected: + PhysicsShapeEdgeBox(); + virtual ~PhysicsShapeEdgeBox(); + + friend class PhysicsBody; }; /** a chain shape */ @@ -332,14 +328,12 @@ public: protected: bool init(const Vec2* points, int count, const PhysicsMaterial& material = PHYSICSSHAPE_MATERIAL_DEFAULT, float border = 1); + virtual void update(float delta) override; protected: PhysicsShapeEdgeChain(); virtual ~PhysicsShapeEdgeChain(); - -protected: - Vec2 _center; - + friend class PhysicsBody; }; From fccc517eef8ed90270ae570fa0345c143c7ff03c Mon Sep 17 00:00:00 2001 From: boyu0 Date: Fri, 27 Jun 2014 17:30:50 +0800 Subject: [PATCH 2/2] add test for physics transform. --- .../Classes/PhysicsTest/PhysicsTest.cpp | 80 ++++++++++++++++++- .../Classes/PhysicsTest/PhysicsTest.h | 12 +++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp index 714d3b1fef..926d5a1ccb 100644 --- a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp +++ b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp @@ -21,6 +21,7 @@ namespace CL(PhysicsPositionRotationTest), CL(PhysicsSetGravityEnableTest), CL(Bug5482), + CL(PhysicsTransformTest), #else CL(PhysicsDemoDisabled), #endif @@ -1593,7 +1594,7 @@ void PhysicsPositionRotationTest::onEnter() auto leftBall = Sprite::create("Images/ball.png"); leftBall->setPosition(-30, 0); leftBall->cocos2d::Node::setScale(2); - leftBall->setPhysicsBody(PhysicsBody::createCircle(leftBall->getContentSize().width/4)); + leftBall->setPhysicsBody(PhysicsBody::createCircle(leftBall->getContentSize().width)); leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG); parent->addChild(leftBall); @@ -1734,4 +1735,81 @@ std::string Bug5482::subtitle() const return "change physics body to the other."; } +bool PhysicsTransformTest::onTouchBegan(Touch *touch, Event *event) +{ + Node* child = this->getChildByTag(1); + child->setPosition(this->convertTouchToNodeSpace(touch)); + return false; +} + +void PhysicsTransformTest::onEnter() +{ + PhysicsDemo::onEnter(); + _scene->toggleDebug(); + _scene->getPhysicsWorld()->setGravity(Point::ZERO); + + auto touchListener = EventListenerTouchOneByOne::create(); + touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this); + _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this); + + auto wall = Node::create(); + wall->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f))); + wall->setPosition(VisibleRect::center()); + addChild(wall); + + //parent test + auto parent = Sprite::create("Images/YellowSquare.png"); + parent->setPosition(200, 100); + parent->setScale(0.25); + parent->setPhysicsBody(PhysicsBody::createBox(parent->getContentSize()*parent->getScale(), PhysicsMaterial(0.1f, 1.0f, 0.0f))); + parent->getPhysicsBody()->setTag(DRAG_BODYS_TAG); + parent->setTag(1); + addChild(parent); + + auto leftBall = Sprite::create("Images/ball.png"); + leftBall->setPosition(-30, 0); + leftBall->cocos2d::Node::setScale(2); + leftBall->setPhysicsBody(PhysicsBody::createCircle(leftBall->getContentSize().width, PhysicsMaterial(0.1f, 1.0f, 0.0f))); + leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG); + parent->addChild(leftBall); + + ScaleTo* scaleTo = ScaleTo::create(2.0, 0.5); + ScaleTo* scaleBack = ScaleTo::create(2.0, 1.0); + parent->runAction(RepeatForever::create(Sequence::create(scaleTo, scaleBack, nullptr))); + + auto normal = Sprite::create("Images/YellowSquare.png"); + normal->setPosition(300, 100); + normal->setScale(0.25, 0.5); + auto size = parent->getContentSize(); + size.width *= normal->getScaleX(); + size.height *= normal->getScaleY(); + normal->setPhysicsBody(PhysicsBody::createBox(size, PhysicsMaterial(0.1f, 1.0f, 0.0f))); + normal->getPhysicsBody()->setTag(DRAG_BODYS_TAG); + addChild(normal); + + auto bullet = Sprite::create("Images/ball.png"); + bullet->setPosition(200, 200); + bullet->setPhysicsBody(PhysicsBody::createCircle(bullet->getContentSize().width/2, PhysicsMaterial(0.1f, 1.0f, 0.0f))); + bullet->getPhysicsBody()->setVelocity(Vect(100, 100)); + this->addChild(bullet); + + + MoveBy* move = MoveBy::create(2.0, Vec2(100, 100)); + MoveBy* move2 = MoveBy::create(2.0, Vec2(-200, 0)); + MoveBy* move3 = MoveBy::create(2.0, Vec2(100, -100)); + ScaleTo* scale = ScaleTo::create(3.0, 0.3); + ScaleTo* scale2 = ScaleTo::create(3.0, 1.0); + + RotateBy* rotate = RotateBy::create(6.0, 360); + + this->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr))); + this->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr))); + this->runAction(RepeatForever::create(rotate)); +} + +std::string PhysicsTransformTest::title() const +{ + return "Physics transform test"; +} + #endif // ifndef CC_USE_PHYSICS diff --git a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.h b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.h index e32a1ebf16..3ff0ca0044 100644 --- a/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.h +++ b/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.h @@ -255,6 +255,18 @@ private: bool _bodyInA; }; +class PhysicsTransformTest : public PhysicsDemo +{ +public: + CREATE_FUNC(PhysicsTransformTest); + + void onEnter() override; + virtual std::string title() const override; + + bool onTouchBegan(Touch* touch, Event* event); + +}; + #endif #endif