Search code examples
c#math.net-4.0xna

2D orbit increasing over time


I have a method for orbiting a sprite (fleet) around another sprite (planet). The problem is that, over time, the fleet moves further away (very slowly, almost unnoticeable unless you let the orbit run for a few minutes).

public void Orbit()
{
    // Planet's position - fleet position
    Vector2 distanceToDestination = currentLocation.Position - position;

    // Calculate fleet's rotation ( - right angle so fleet rotates clockwise)
    rotation = MathHelper.WrapAngle((float)Math.Atan2(distanceToDestination.Y, distanceToDestination.X)) - Helpers.RightAngle;

    // Get the direction that the fleet is facing
    direction = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));

    // Fleet position, thrust is set to 0.4f
    position = Vector2.Add(position, direction * thrust);

    // Fleet rectangle
    rect = new Rectangle((int)position.X, (int)position.Y, fleetTexture.Width, fleetTexture.Height);
}

public static class Helpers
{
    public const float RightAngle = (float)Math.PI / 2;
}

I would be grateful if the community could point out why my fleet is not maintaining a consistent orbit, which is what I want to achieve! Many thanks in advance.


Solution

  • If I understand what you are doing, you are trying to simulate orbital physics using a model sort of like that of a car driving around a circle (i.e. you're not modeling the acceleration of gravity perpendicular to the current velocity and numerically integrating it). Instead, you're doing this:

    1. Move perpendicular to the center of the circle of radiusr by a small amount d
    2. Reorient so the "car" is still facing perpendicular to the center of the circle.
    3. Repeat.

    Now, after each step, how far is your object from the center of the circle? Well, by the Pythagorean theorem, it's sqrt(r*r + d*d), which is going to be slightly larger than r. Using a very large value for d for emphasis:

    enter image description here

    That should account for your drift.

    Incidentally, you don't need to use trig functions to construct a perpendicular to the distanceToDestination. It is much easier to simply cross it with the ±Z vector, the result will be (in 2d) ±(-distanceToDestination.Y, distanceToDestination.X).

    Update: since you're not really simulating orbital physics, why not solve the problem analytically?

        public static Vector2 Orbit(Vector2 center, Vector2 startPos, float speed, float time)
        {
            // positive speed means CCW around the center, negative means CW.
            var radiusVec = (startPos - center);
            var radius = radiusVec.Length();
            var angularVelocity = speed / radius; // Add check for divide by zero
            Vector2 perpendicularVec = new Vector2(-radiusVec.Y, radiusVec.X);
            return center + (float)Math.Cos(time * angularVelocity) * radiusVec + (float)Math.Sin(time * angularVelocity) * perpendicularVec;
        }