Merge pull request #11379 from WenhaiLin/v3-physics-fix

Physics: Fixed position of physics body is wrong when the position of parent node changes
This commit is contained in:
minggo 2015-04-10 16:45:45 +08:00
commit 698d93a42b
5 changed files with 82 additions and 35 deletions

View File

@ -127,6 +127,8 @@ Node::Node(void)
, _physicsRotation(0.0f) , _physicsRotation(0.0f)
, _physicsTransformDirty(true) , _physicsTransformDirty(true)
, _updateTransformFromPhysics(true) , _updateTransformFromPhysics(true)
, _physicsWorld(nullptr)
, _physicsBodyAssociatedWith(0)
#endif #endif
, _displayedOpacity(255) , _displayedOpacity(255)
, _realOpacity(255) , _realOpacity(255)
@ -334,8 +336,9 @@ void Node::setRotation(float rotation)
_rotationZ_X = _rotationZ_Y = rotation; _rotationZ_X = _rotationZ_Y = rotation;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
@ -475,8 +478,9 @@ void Node::setScale(float scale)
_scaleX = _scaleY = _scaleZ = scale; _scaleX = _scaleY = _scaleZ = scale;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -497,8 +501,9 @@ void Node::setScale(float scaleX,float scaleY)
_scaleY = scaleY; _scaleY = scaleY;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -512,8 +517,9 @@ void Node::setScaleX(float scaleX)
_scaleX = scaleX; _scaleX = scaleX;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -556,8 +562,9 @@ void Node::setScaleY(float scaleY)
_scaleY = scaleY; _scaleY = scaleY;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -592,8 +599,9 @@ void Node::setPosition(float x, float y)
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
_usingNormalizedPosition = false; _usingNormalizedPosition = false;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -661,8 +669,9 @@ void Node::setNormalizedPosition(const Vec2& position)
_normalizedPositionDirty = true; _normalizedPositionDirty = true;
_transformUpdated = _transformDirty = _inverseDirty = true; _transformUpdated = _transformDirty = _inverseDirty = true;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
if (_physicsBody && _physicsBody->getWorld()) { if (_physicsWorld && _physicsBodyAssociatedWith > 0)
_physicsBody->getWorld()->_updateBodyTransform = true; {
_physicsWorld->_updateBodyTransform = true;
} }
#endif #endif
} }
@ -1050,8 +1059,17 @@ void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::stri
child->setOrderOfArrival(s_globalOrderOfArrival++); child->setOrderOfArrival(s_globalOrderOfArrival++);
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
_physicsBodyAssociatedWith += child->_physicsBodyAssociatedWith;
auto parentNode = this;
while (parentNode->_parent)
{
parentNode = parentNode->_parent;
parentNode->_physicsBodyAssociatedWith += child->_physicsBodyAssociatedWith;
}
auto scene = dynamic_cast<Scene*>(parentNode);
// Recursive add children with which have physics body. // Recursive add children with which have physics body.
auto scene = this->getScene();
if (scene && scene->getPhysicsWorld()) if (scene && scene->getPhysicsWorld())
{ {
scene->addChildToPhysicsWorld(child); scene->addChildToPhysicsWorld(child);
@ -2029,6 +2047,14 @@ void Node::setPhysicsBody(PhysicsBody* body)
_physicsBody->_node = nullptr; _physicsBody->_node = nullptr;
_physicsBody->release(); _physicsBody->release();
_physicsBody = nullptr; _physicsBody = nullptr;
_physicsBodyAssociatedWith--;
auto parentNode = this;
while (parentNode->_parent)
{
parentNode = parentNode->_parent;
parentNode->_physicsBodyAssociatedWith--;
}
} }
if (body) if (body)
@ -2053,7 +2079,15 @@ void Node::setPhysicsBody(PhysicsBody* body)
_physicsScaleStartX = _scaleX; _physicsScaleStartX = _scaleX;
_physicsScaleStartY = _scaleY; _physicsScaleStartY = _scaleY;
auto scene = getScene(); _physicsBodyAssociatedWith++;
auto parentNode = this;
while (parentNode->_parent)
{
parentNode = parentNode->_parent;
parentNode->_physicsBodyAssociatedWith++;
}
auto scene = dynamic_cast<Scene*>(parentNode);
if (scene && scene->getPhysicsWorld()) if (scene && scene->getPhysicsWorld())
{ {
_physicsTransformDirty = true; _physicsTransformDirty = true;
@ -2095,6 +2129,7 @@ void Node::updateTransformFromPhysics(const Mat4& parentTransform, uint32_t pare
{ {
auto& newPosition = _physicsBody->getPosition(); auto& newPosition = _physicsBody->getPosition();
auto& recordedPosition = _physicsBody->_recordedPosition; auto& recordedPosition = _physicsBody->_recordedPosition;
auto updateBodyTransform = _physicsWorld->_updateBodyTransform;
if (parentFlags || recordedPosition.x != newPosition.x || recordedPosition.y != newPosition.y) if (parentFlags || recordedPosition.x != newPosition.x || recordedPosition.y != newPosition.y)
{ {
recordedPosition = newPosition; recordedPosition = newPosition;
@ -2105,6 +2140,7 @@ void Node::updateTransformFromPhysics(const Mat4& parentTransform, uint32_t pare
} }
_physicsRotation = _physicsBody->getRotation(); _physicsRotation = _physicsBody->getRotation();
setRotation(_physicsRotation - _parent->_physicsRotation); setRotation(_physicsRotation - _parent->_physicsRotation);
_physicsWorld->_updateBodyTransform = updateBodyTransform;
} }
#endif //CC_USE_PHYSICS #endif //CC_USE_PHYSICS

View File

@ -54,6 +54,7 @@ class GLProgram;
class GLProgramState; class GLProgramState;
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
class PhysicsBody; class PhysicsBody;
class PhysicsWorld;
#endif #endif
/** /**
@ -1838,6 +1839,9 @@ protected:
float _physicsRotation; float _physicsRotation;
bool _physicsTransformDirty; bool _physicsTransformDirty;
bool _updateTransformFromPhysics; bool _updateTransformFromPhysics;
PhysicsWorld* _physicsWorld; /** The PhysicsWorld associated with the node.*/
int _physicsBodyAssociatedWith; /** The count of PhysicsBody associated with the node and children.*/
#endif #endif
// opacity controls // opacity controls
@ -1862,7 +1866,7 @@ private:
CC_DISALLOW_COPY_AND_ASSIGN(Node); CC_DISALLOW_COPY_AND_ASSIGN(Node);
#if CC_USE_PHYSICS #if CC_USE_PHYSICS
friend class Layer; friend class Scene;
#endif //CC_USTPS #endif //CC_USTPS
}; };

View File

@ -227,6 +227,8 @@ void Scene::addChildToPhysicsWorld(Node* child)
std::function<void(Node*)> addToPhysicsWorldFunc = nullptr; std::function<void(Node*)> addToPhysicsWorldFunc = nullptr;
addToPhysicsWorldFunc = [this, &addToPhysicsWorldFunc](Node* node) -> void addToPhysicsWorldFunc = [this, &addToPhysicsWorldFunc](Node* node) -> void
{ {
node->_physicsWorld = _physicsWorld;
if (node->getPhysicsBody()) if (node->getPhysicsBody())
{ {
_physicsWorld->addBody(node->getPhysicsBody()); _physicsWorld->addBody(node->getPhysicsBody());

View File

@ -1716,8 +1716,7 @@ std::string PhysicsFixedUpdate::subtitle() const
bool PhysicsTransformTest::onTouchBegan(Touch *touch, Event *event) bool PhysicsTransformTest::onTouchBegan(Touch *touch, Event *event)
{ {
Node* child = this->getChildByTag(1); _parentSprite->setPosition(_rootLayer->convertTouchToNodeSpace(touch));
child->setPosition(this->convertTouchToNodeSpace(touch));
return false; return false;
} }
@ -1731,46 +1730,49 @@ void PhysicsTransformTest::onEnter()
touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this); touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
_rootLayer = Layer::create();
addChild(_rootLayer);
auto wall = Node::create(); auto wall = Node::create();
wall->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f))); wall->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
wall->setPosition(VisibleRect::center()); wall->setPosition(VisibleRect::center());
addChild(wall); _rootLayer->addChild(wall);
//parent test //parent test
auto parent = Sprite::create("Images/YellowSquare.png"); _parentSprite = Sprite::create("Images/YellowSquare.png");
parent->setPosition(200, 100); _parentSprite->setPosition(200, 100);
parent->setScale(0.25); _parentSprite->setScale(0.25);
parent->setPhysicsBody(PhysicsBody::createBox(parent->getContentSize()*parent->getScale(), PhysicsMaterial(0.1f, 1.0f, 0.0f))); _parentSprite->setPhysicsBody(PhysicsBody::createBox(_parentSprite->getContentSize()*_parentSprite->getScale(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
parent->getPhysicsBody()->setTag(DRAG_BODYS_TAG); _parentSprite->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
parent->setTag(1); _parentSprite->setTag(1);
addChild(parent); _rootLayer->addChild(_parentSprite);
auto leftBall = Sprite::create("Images/ball.png"); auto leftBall = Sprite::create("Images/ball.png");
leftBall->setPosition(-30, 0); leftBall->setPosition(-30, 0);
leftBall->cocos2d::Node::setScale(2); leftBall->cocos2d::Node::setScale(2);
leftBall->setPhysicsBody(PhysicsBody::createCircle(leftBall->getContentSize().width, PhysicsMaterial(0.1f, 1.0f, 0.0f))); leftBall->setPhysicsBody(PhysicsBody::createCircle(leftBall->getContentSize().width, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG); leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
parent->addChild(leftBall); _parentSprite->addChild(leftBall);
ScaleTo* scaleTo = ScaleTo::create(2.0, 0.5); ScaleTo* scaleTo = ScaleTo::create(2.0, 0.5);
ScaleTo* scaleBack = ScaleTo::create(2.0, 1.0); ScaleTo* scaleBack = ScaleTo::create(2.0, 1.0);
parent->runAction(RepeatForever::create(Sequence::create(scaleTo, scaleBack, nullptr))); _parentSprite->runAction(RepeatForever::create(Sequence::create(scaleTo, scaleBack, nullptr)));
auto normal = Sprite::create("Images/YellowSquare.png"); auto normal = Sprite::create("Images/YellowSquare.png");
normal->setPosition(300, 100); normal->setPosition(300, 100);
normal->setScale(0.25, 0.5); normal->setScale(0.25, 0.5);
auto size = parent->getContentSize(); auto size = _parentSprite->getContentSize();
size.width *= normal->getScaleX(); size.width *= normal->getScaleX();
size.height *= normal->getScaleY(); size.height *= normal->getScaleY();
normal->setPhysicsBody(PhysicsBody::createBox(size, PhysicsMaterial(0.1f, 1.0f, 0.0f))); normal->setPhysicsBody(PhysicsBody::createBox(size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
normal->getPhysicsBody()->setTag(DRAG_BODYS_TAG); normal->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
addChild(normal); _rootLayer->addChild(normal);
auto bullet = Sprite::create("Images/ball.png"); auto bullet = Sprite::create("Images/ball.png");
bullet->setPosition(200, 200); bullet->setPosition(200, 200);
bullet->setPhysicsBody(PhysicsBody::createCircle(bullet->getContentSize().width/2, PhysicsMaterial(0.1f, 1.0f, 0.0f))); bullet->setPhysicsBody(PhysicsBody::createCircle(bullet->getContentSize().width/2, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
bullet->getPhysicsBody()->setVelocity(Vect(100, 100)); bullet->getPhysicsBody()->setVelocity(Vect(100, 100));
this->addChild(bullet); _rootLayer->addChild(bullet);
MoveBy* move = MoveBy::create(2.0f, Vec2(100, 100)); MoveBy* move = MoveBy::create(2.0f, Vec2(100, 100));
@ -1781,9 +1783,9 @@ void PhysicsTransformTest::onEnter()
RotateBy* rotate = RotateBy::create(6.0f, 360); RotateBy* rotate = RotateBy::create(6.0f, 360);
this->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr))); _rootLayer->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr)));
this->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr))); _rootLayer->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr)));
this->runAction(RepeatForever::create(rotate)); _rootLayer->runAction(RepeatForever::create(rotate));
} }
std::string PhysicsTransformTest::title() const std::string PhysicsTransformTest::title() const

View File

@ -259,6 +259,9 @@ public:
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event); bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
private:
cocos2d::Sprite* _parentSprite;
cocos2d::Layer* _rootLayer;
}; };
class PhysicsIssue9959 : public PhysicsDemo class PhysicsIssue9959 : public PhysicsDemo