2
\$\begingroup\$

I have a problem with rotation of my hero in 2D space. The hero is made of body parts such as: head, arms etc. Every part is a separate sprite. When I want to rotate the hero, I have to rotate all of its parts.

I know the hero position, and I save the parts positions as:

head = (heroPosition.x+20, heroPosition.y+20)

In other words I know the positions of all parts while the hero was not rotated. After rotation I know only the hero position and the rotation angle(Grades).

How can I calculate the new position for each part?

Problem ilustration

\$\endgroup\$
3
\$\begingroup\$

This problem is called Forward Kinematics. To solve this problem in general, I recommend creating what is called a Kinematic Chain, or Kinematic Tree. To do this, you will need knowledge of a 2D rotation matrix, or transformation matrix.

A 2D 3x3 transformation matrix is defined as:

H = [xx, xy, tx;
     yx, yy, ty;
      0,  0,  1];

In this case, [xx, yx] represents the x axis of the transformation, [xy, yy] represents the y axis, and [tx, ty] represents the translation of the transformation. For instance, the transformation:

    H = [1, 0, 1;
         0, 1, 0.5;
         0, 0, 1];

translates a part 1 unit in the x direction, and 0.5 units in the y direction. To transform any vector, just pre-mulltiply it by the transformation matrix H. A special case of the transformation matrix is the rotation matrix. In 2D, a pure rotation can be represented as:

H = [cos(theta), -sin(theta), 0;
     sin(theta),  cos(theta), 0;
              0,           0, 1];

where theta is the rotation value in Radians.

Now, to implement a Kinematic tree, you just need to do this:

// Represents a rigid link in a kinematic chain
class Link
{
  public:
    // All links have exactly one or zero parent links. 
    // The "root" of the tree has no parent (NULL)
    Link* parent;
    // All links can have as many children as needed
    std::vector<Link*> children;

    // Represents the transform from the parent link to
    // this link.
    Matrix3x3 localTransform;
    // Reprsents the transform from the world to this link.
    Matrix3x3 globalTransform;


    // Computes the global transform of this link with respect
    // to the world. Then computes the global transforms of all
    // children.
    void ComputeTransformsRecursive()
    {
       // If we're the root link, the global transform is the local transform.
       if(!parent) globalTransform = localTransform;
       else
       {
           // Otherwise, the global transform is the parent's global transform
           // times our transform (matrix multiplication)
           globalTransform = parent->globalTransform * localTransform;


           // Now recursively compute the global transform for each of the children
           for (Link* link : children)
           {
               link->ComputeTransformsRecursive();
           }
       }
    }

}

To build the kinematic tree for your character, you just do this:

// The body is the base link, and starts at (0, 0) with 0 rotation.
Link* bodyLink = new Link();
bodyLink->parent = NULL;
bodyLink->localTransform = Matrix3x3::Identity();

// The left arm, relative to the body, is 50 pixels to the right and 10 up,
// with no local rotation.
Link* leftArm = new Link();
leftArm->parent = bodyLink;
leftArm->localTransform = Matrix3x3::CreateTranslation(50, 10);
bodyLink.children.push_back(leftArm);


// The right arm is 50 right and 10 down.
Link* rightArm= new Link();
rightArm->parent = bodyLink;
rightArm->localTransform = Matrix3x3::CreateTranslation(50, -10);
bodyLink.children.push_back(rightArm);

// The head is 10 right and 0 down
Link* head = new Link();
head->parent = bodyLink;
head->localTransform = Matrix3x3::CreateTranslation(10, 0);
bodyLink.children.push_back(head);

You can rotate/translate the entire character just by moving around the body link:

bodyLink->localTransform.translation = Vector2(xPosition, yPosition);
bodyLink->localTransform.rotation = theta;

Then, to update, you just need to do this:

bodyLink->ComputeTransformsRecursive();

From there, you automatically get the global transforms (their rotations and translations):

Matrix3x3 headTransform     = head->globalTransform;
Matrix3x3 leftArmTransform  = leftArm->globalTransform;
Matrix3x3 rightArmTransform = rightArm->globalTransform;

You can also attach/detach nodes to different parts of the body to do things like make the character hold a gun, for instance.

\$\endgroup\$
1
\$\begingroup\$

You need to move each part to 0,0 then rotate them, then move them back. Without doing this they just rotate around 20 units fron your character

\$\endgroup\$
0
\$\begingroup\$

For each part, it need to have an offset to the hero location. Eg, +20, +20. Its correct position when hero rotation is r is heroPosition.x + rotated(offsetX, r) and same for y. See http://en.wikipedia.org/wiki/Rotation_matrix for more info.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .