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

View File

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

View File

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

View File

@ -1716,8 +1716,7 @@ std::string PhysicsFixedUpdate::subtitle() const
bool PhysicsTransformTest::onTouchBegan(Touch *touch, Event *event)
{
Node* child = this->getChildByTag(1);
child->setPosition(this->convertTouchToNodeSpace(touch));
_parentSprite->setPosition(_rootLayer->convertTouchToNodeSpace(touch));
return false;
}
@ -1731,46 +1730,49 @@ void PhysicsTransformTest::onEnter()
touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
_rootLayer = Layer::create();
addChild(_rootLayer);
auto wall = Node::create();
wall->setPhysicsBody(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
wall->setPosition(VisibleRect::center());
addChild(wall);
_rootLayer->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);
_parentSprite = Sprite::create("Images/YellowSquare.png");
_parentSprite->setPosition(200, 100);
_parentSprite->setScale(0.25);
_parentSprite->setPhysicsBody(PhysicsBody::createBox(_parentSprite->getContentSize()*_parentSprite->getScale(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
_parentSprite->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
_parentSprite->setTag(1);
_rootLayer->addChild(_parentSprite);
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);
_parentSprite->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)));
_parentSprite->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();
auto size = _parentSprite->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);
_rootLayer->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);
_rootLayer->addChild(bullet);
MoveBy* move = MoveBy::create(2.0f, Vec2(100, 100));
@ -1781,9 +1783,9 @@ void PhysicsTransformTest::onEnter()
RotateBy* rotate = RotateBy::create(6.0f, 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));
_rootLayer->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr)));
_rootLayer->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr)));
_rootLayer->runAction(RepeatForever::create(rotate));
}
std::string PhysicsTransformTest::title() const

View File

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