issue #4150: Correct body position with the node has a parent. Add set/getPosition/Rotation method.

This commit is contained in:
boyu0 2014-02-28 15:31:25 +08:00
parent ab9f030b11
commit a934d29c57
4 changed files with 93 additions and 23 deletions

View File

@ -419,7 +419,9 @@ void Node::setPosition(const Point& position)
#if CC_USE_PHYSICS
if (_physicsBody)
{
_physicsBody->setPosition(position);
Node* parent = getParent();
Point pos = parent != nullptr ? parent->convertToWorldSpace(getPosition()) : getPosition();
_physicsBody->setPosition(pos);
}
#endif
}
@ -534,6 +536,14 @@ const Point& Node::getAnchorPoint() const
void Node::setAnchorPoint(const Point& point)
{
#if CC_USE_PHYSICS
if (_physicsBody != nullptr && point.equals(Point::ANCHOR_MIDDLE))
{
CCLOG("Node warning: This node has a physics body, the anchor must be in the middle, you cann't change this to other value.");
return;
}
#endif
if( ! point.equals(_anchorPoint))
{
_anchorPoint = point;
@ -719,6 +729,11 @@ void Node::addChild(Node *child, int zOrder, int tag)
this->insertChild(child, zOrder);
#if CC_USE_PHYSICS
if (child->getPhysicsBody() != nullptr)
{
child->getPhysicsBody()->setPosition(this->convertToWorldSpace(child->getPosition()));
}
for (Node* node = this->getParent(); node != nullptr; node = node->getParent())
{
if (dynamic_cast<Scene*>(node) != nullptr)
@ -1511,6 +1526,14 @@ void Node::setPhysicsBody(PhysicsBody* body)
{
body->_node = this;
body->retain();
// physics rotation based on body position, but node rotation based on node anthor point
// it cann't support both of them, so I clear the anthor point to default.
if (!getAnchorPoint().equals(Point::ANCHOR_MIDDLE))
{
CCLOG("Node warning: setPhysicsBody sets anchor point to Point::ANCHOR_MIDDLE.");
setAnchorPoint(Point::ANCHOR_MIDDLE);
}
}
if (_physicsBody != nullptr)
@ -1529,7 +1552,9 @@ void Node::setPhysicsBody(PhysicsBody* body)
_physicsBody = body;
if (body != nullptr)
{
_physicsBody->setPosition(getPosition());
Node* parent = getParent();
Point pos = parent != nullptr ? parent->convertToWorldSpace(getPosition()) : getPosition();
_physicsBody->setPosition(pos);
_physicsBody->setRotation(getRotation());
}
}

View File

@ -449,6 +449,7 @@ public:
* The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner.
* But you can use values higher than (1,1) and lower than (0,0) too.
* The default anchorPoint is (0.5,0.5), so it starts in the center of the node.
* @note If node has a physics body, the anchor must be in the middle, you cann't change this to other value.
*
* @param anchorPoint The anchor point of node.
*/
@ -1432,6 +1433,7 @@ public:
#if CC_USE_PHYSICS
/**
* set the PhysicsBody that let the sprite effect with physics
* @note This method will set anchor point to Point::ANCHOR_MIDDLE if body not null, and you cann't change anchor point if node has a physics body.
*/
void setPhysicsBody(PhysicsBody* body);

View File

@ -75,6 +75,7 @@ PhysicsBody::PhysicsBody()
, _group(0)
, _positionResetTag(false)
, _rotationResetTag(false)
, _rotationOffset(0)
{
}
@ -347,7 +348,7 @@ void PhysicsBody::setPosition(Point position)
{
if (!_positionResetTag)
{
cpBodySetPos(_info->getBody(), PhysicsHelper::point2cpv(position));
cpBodySetPos(_info->getBody(), PhysicsHelper::point2cpv(position + _positionOffset));
}
_positionResetTag = false;
}
@ -356,7 +357,7 @@ void PhysicsBody::setRotation(float rotation)
{
if (!_rotationResetTag)
{
cpBodySetAngle(_info->getBody(), -PhysicsHelper::float2cpfloat(rotation * M_PI / 180.0f));
cpBodySetAngle(_info->getBody(), -PhysicsHelper::float2cpfloat((rotation + _rotationOffset) * (M_PI / 180.0f)));
}
_rotationResetTag = false;
@ -365,12 +366,12 @@ void PhysicsBody::setRotation(float rotation)
Point PhysicsBody::getPosition() const
{
cpVect vec = cpBodyGetPos(_info->getBody());
return PhysicsHelper::cpv2point(vec);
return PhysicsHelper::cpv2point(vec) - _positionOffset;
}
float PhysicsBody::getRotation() const
{
return -PhysicsHelper::cpfloat2float(cpBodyGetAngle(_info->getBody()) / M_PI * 180.0f);
return -PhysicsHelper::cpfloat2float(cpBodyGetAngle(_info->getBody()) * (180.0f / M_PI)) - _rotationOffset;
}
PhysicsShape* PhysicsBody::addShape(PhysicsShape* shape, bool addMassAndMoment/* = true*/)
@ -767,27 +768,18 @@ void PhysicsBody::setResting(bool rest) const
void PhysicsBody::update(float delta)
{
if (_node != nullptr && _dynamic && !isResting())
if (_node != nullptr)
{
cpVect pos = cpBodyGetPos(_info->getBody());
cpVect prePos = _info->getPosition();
cpVect rot = cpBodyGetRot(_info->getBody());
cpVect preRot = _info->getRotation();
Node* parent = _node->getParent();
// only reset the node position when body position/rotation changed.
if (std::abs(pos.x - prePos.x) >= 0.3f || std::abs(pos.y - prePos.y) >= 0.3f
|| std::abs(rot.x - preRot.x) >= 0.01f || std::abs(rot.y - preRot.y) >= 0.01f)
{
_positionResetTag = true;
_rotationResetTag = true;
_node->setPosition(getPosition());
_info->setPosition(pos);
_node->setRotation(getRotation());
_info->setRotation(rot);
}
Point position = parent != nullptr ? parent->convertToNodeSpace(getPosition()) : getPosition();
_positionResetTag = true;
_rotationResetTag = true;
_node->setPosition(position);
_node->setRotation(getRotation());
// damping compute
if (_isDamping)
if (_isDamping && _dynamic && !isResting())
{
_info->getBody()->v.x *= cpfclamp(1.0f - delta * _linearDamping, 0.0f, 1.0f);
_info->getBody()->v.y *= cpfclamp(1.0f - delta * _linearDamping, 0.0f, 1.0f);
@ -834,6 +826,46 @@ void PhysicsBody::setGroup(int group)
}
}
void PhysicsBody::setPositionOffset(const Point& position)
{
if (!_positionOffset.equals(position))
{
Point pos = getPosition();
_positionOffset = position;
if (_node!= nullptr)
{
setPosition(pos);
}
}
}
Point PhysicsBody::getPositionOffset()
{
return _positionOffset;
}
void PhysicsBody::setRotationOffset(float rotation)
{
if (std::abs(_rotationOffset - rotation) > 0.5f)
{
float rot = getRotation();
_rotationOffset = rotation;
if (_node != nullptr)
{
setRotation(rot);
}
}
}
float PhysicsBody::getRotationOffset()
{
return _rotationOffset;
}
Point PhysicsBody::world2Local(const Point& point)
{
return PhysicsHelper::cpv2point(cpBodyWorld2Local(_info->getBody(), PhysicsHelper::point2cpv(point)));

View File

@ -192,6 +192,15 @@ public:
/** get the body rotation. */
float getRotation() const;
/** set body position offset, it's the position witch relative to node */
void setPositionOffset(const Point& position);
/** get body position offset. */
Point getPositionOffset();
/** set body rotation offset, it's the rotation witch relative to node */
void setRotationOffset(float rotation);
/** set the body rotation offset */
float getRotationOffset();
/**
* @brief test the body is dynamic or not.
* a dynamic body will effect with gravity.
@ -332,6 +341,8 @@ protected:
bool _positionResetTag; /// To avoid reset the body position when body invoke Node::setPosition().
bool _rotationResetTag; /// To avoid reset the body rotation when body invoke Node::setRotation().
Point _positionOffset;
float _rotationOffset;
friend class PhysicsWorld;
friend class PhysicsShape;