2
\$\begingroup\$

In my game I have programmed Body and Limb classes. The Body is guaranteed to have an origin in the center of its sprite. The Body class has a List of children Limbs, each with their own offset. Every Limb has a Master value which references the parent Body, but it also has a Parent value which references the Limb it is a child of. However, Limbs do not have to have a parent, they can directly connect to the Body.

The Master, Parent, and Children values of the Limb class:

    //Body containing all limbs this limb is connected to and others.
    public Body Master
    { get; set; }

    //Parent limb, if null then limb directly connected to the body.
    public Limb Parent
    { get; set; }

    //Children limbs
    public List<Limb> Children
    { get; set; }

The Limb methods have if statements to handle these situations. In relation to the offsets and rotations of the Limbs around the Body (using transformation matrices) things seem to work fine. Now, the problem I'm having is when a Limb is attached to another Limb. The child Limb draws and behaves as if it is rotating around the Body instead of its parent Limb, and the parent Limb itself vanishes. Limbs without Children that are directly connected to the Master Body have no issues. Because of this sort of recursive hierarchy I believe the problem has to do with reference types but I may be mistaken. Here is some additional code:

Demonstration:

enter image description here

Here is the worldPosition() method which is used to acquire the Limb's position in world space. I suspect it may be the culprit. The Master.Position is already in world space:

    public Vector2 worldPosition()
    {
        if (Parent != null) return (LocalPosition += Parent.worldPosition());
        else return (LocalPosition += Master.Position);
    }

Finally here is the Update() method of the Limb class: http://pastebin.com/5L5v5p6x

EDIT: Upon further analysis it appears that any changes I make to either Limb seem to affect the other Limb in one way or another even though they are both quite clearly different instances.

Here is the code to make the initial Body and first Limb:

        b = new Body()
        {
            Sprite = FileFactory.Textures["shoulders"],
            Position = new Vector2(this.Position.X, this.Position.Y),
        };

        Limb l = new Limb()
        {
            Sprite = FileFactory.Textures["left_arm"],
            Master = b,
            Offset = new Vector2(2, 13),
            Origin = new Vector2(0, Sprite.Height / 2),
            RotationalDifference = (float)(0.2 * Math.PI),
            RotateSpeed = 0.15f
        };

        b.Children.Add(l);
        b.Initialize();

And the code to add the child Limb to the first (Parent) Limb:

            Children.Add(
            new Limb()
            {
                Sprite = FileFactory.Textures["right_arm"],
                Master = this.Master,
                Parent = this,
                Offset = new Vector2(27, 0),
                Origin = new Vector2(0, Sprite.Height / 2),
                RotationalDifference = (float)(0.2 * Math.PI),
                RotateSpeed = 0.15f
            }
            );
\$\endgroup\$
  • \$\begingroup\$ Standard-ish debugging questions: What's the simplest case that still works? What's the simplest that breaks? \$\endgroup\$ – Anko Apr 23 '14 at 21:49
  • \$\begingroup\$ The simplest case that works is when the Limbs don't have children. Suddenly when a child is added to a limb it breaks so that would be the simplest case that breaks. \$\endgroup\$ – Bagofsheep Apr 23 '14 at 21:53
  • \$\begingroup\$ You can simplify futher to isolate further: What happens when you do super-simple rendering (like just drawing lines or untransformed sprites)? \$\endgroup\$ – Anko Apr 23 '14 at 21:58
  • \$\begingroup\$ Well I commented out the lines that transform the Limbs and even the child Limb vanishes after that. Now there is no arm whatsoever. \$\endgroup\$ – Bagofsheep Apr 23 '14 at 22:01
  • \$\begingroup\$ When I comment out the code that adds the new child Limb to the Limb directly attached to the Body, the Limb directly attached to the body reappears. This is part of the reason why I think worldPosition() is the culprit because of the way it works, but I can't figure out why. \$\endgroup\$ – Bagofsheep Apr 23 '14 at 22:23
0
\$\begingroup\$

As it turns out, the problem is in this code here:

public Vector2 worldPosition()
{
    if (Parent != null) return (LocalPosition += Parent.worldPosition());
    else return (LocalPosition += Master.Position);
}

I was using the wrong operator, += instead of just +. I was continually adding one position to the other and returning the accumulating result. It's hilarious that it took somebody else to notice it and only after 2 days of the problem arising. The working code looks like this:

public Vector2 worldPosition()
{
    if (Parent != null) return (LocalPosition + Parent.worldPosition());
    else return (LocalPosition + Master.Position);
}
| improve this answer | |
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.