Fixed joints around a planet

Sep 28, 2011 at 5:07 PM

This problem is a little hard to explain with text and pictures, so heres a video http://www.youtube.com/watch?v=jXLvBWDbsxo

Im creating a platformer game where the level select will be a planet that you walk around to get to each level. I have the planet and gravity created, and im using the usual platformer character (a box on a circle, with a fixed joint to keep the box straight). The problem im having is that the fixed joint needs to remain perpendicular to the angle between the centre of the planet, and the centre of the circle shape of the character. Everything is working fine until the player reaches the point where the shape goes from 180 degrees to -180 degrees cause the fixed joint angle is trying to go from 270 degrees to -90 degrees, and makes the character do a full flip and get flung away from the planet.

// Calculate the angle from centre of the planet to the character
double dx = character.wheel.Position.X - planet.Position.X;
double dy = character.wheel.Position.Y - planet.Position.Y;
float angle = (float)Math.Atan2(dy, dx);

// set characters fixed angle to be angle between planet and wheel
// plus 90 degrees (half PI)
character.fixedJoint.TargetAngle = angle+ ((float)Math.PI / 2);
I've tried removing the joint from the world when it reaches this point, setting its new angle then re-adding the joint, but it still seems to make the character flip about. Is there an equation to do this properly, or a better way to do it without fixed joints?

Sep 29, 2011 at 9:11 AM
Edited Sep 29, 2011 at 9:14 AM

add a if after the Atan2 like

if(angle<0)

    angle+=MathHelper.TwoPI;

because Atan2 goes from -180° to 180°

also MathHelper.PiOverTwo ;)

Sep 29, 2011 at 10:44 AM

That solution just moves the problem to the other side. The fixed angle just now tries to go from 450 degrees to 90 degrees so still does the funny flip. Can you think of any solutions that dont involve the fixed joint?

Sep 29, 2011 at 11:20 AM
Edited Sep 29, 2011 at 11:21 AM

hmm it should go from 0-360°

try to add PiOverTwo before the if

but i don't think this fixes the problem :/

Sep 29, 2011 at 5:02 PM

Well yeah it makes the circle go from 0-360, but the characters fixed angle is always 90 more than its position on the outer, to make it stay standing up.

Developer
Sep 29, 2011 at 8:16 PM

Instead of using a joint just set the angular velocity to whatever it needs to be to reach the correct angle for that step. If this doesn't make sense search for the threads on moving bodies by position. I put the formula in one of those threads and it can easily be used for orientation instead of position.

Oct 5, 2011 at 2:05 PM

I believe i found the formula you were refering to, and edited it to fit my situation.

float rotationDelta = character.body.Rotation - (angle + MathHelper.PiOver2);
float rotAngle= ((rotationDelta / (1f / 30f)) * 1);
character.body.AngularVelocity = -rotAngle;

This code kind of works, except the character now looks very wobbly and still has the problem of the circle going from one extreme to the other. The rotation of the rectangle is trying to go from 270 degrees to -90 degrees.

Any other ideas or does it not look hopeful? Thanks in advance.

Apr 30, 2012 at 9:05 AM

I'm having exactly the same problem, i normalize the angle between 0-360 to make sure there aren't any errors but when reach either end  instead of making a smooth  change of position instead it flips all the bodies linked together. i was thinking if i could  use the planet center and some point of reference to make the TargetAngle cumulative so it doesn't jumps back. but that would just be a work around. :(  any help ?

May 1, 2012 at 5:08 AM
Edited May 1, 2012 at 5:12 AM

the answer was really simple. but the body.Sweep is not public

setting the body.Sweep.A to the desire angle will null the step on the solver before you see the targetangle

first we normalize the angle between 0 and 360 so we can detect it easier,

          for (int i= 0; i< this.GameObjects[boneIndex].Lenght; i++)
            {
 
                float offsetangle =anyotherangleinradians;
                rot += MathHelper.ToRadians(this.rotation);
                if ((oldroation < 5 && this.rotation > 355) ||
            (this.rotation < 5 && oldroation > 355))
                {
                    Body BodyA = this.GameObjects[boneIndex].body;

        BodyA.Sweep.A =  (rot);
                
                }

}

oldrotation =  this.rotation;

 

then set the joint target angle to the same as rot

 

*note normalize the angle with  this

        public static float ModAndInvert(float angle, float mod)
        {
            float correctedValue = angle % mod;
            if (correctedValue < 0)
            {
                // Invert the value
                correctedValue = mod - (-correctedValue);
            }
            return correctedValue;
        }