views:

152

answers:

3

I am currently experimenting with some physics toys in XNA using the Farseer Physics library, however my question isn't specific to XNA or Farseer - but to any 2D physics library.

I would like to add "rocket"-like movement (I say rocket-like in the sense that it doesn't have to be a rocket - it could be a plane or a boat on the water or any number of similar situations) for certain objects in my 2D scene. I know how to implement this using a kinematic simulation, but I want to implement it using a dynamic simulation (i.e. applying forces over time). I'm sort of lost on how to implement this.

To simplify things, I don't need the dynamics to rotate the geometry, just to affect the velocity of the body. I'm using a circle geometry that is set to not rotate in Farseer, so I am only concerned with the velocity of the object.

I'm not even sure what the best abstraction should be. Conceptually, I have the direction the body is currently moving (unit vector), a direction I want it to go, and a value representing how fast I want it to change direction, while keeping speed relatively constant (small variations are acceptable).

I could use this abstraction directly, or use something like a "rudder" value which controls how fast the object changes directions (either clockwise or counter clockwise).

What kind of forces should I apply to the body to simulate the movement I'm looking for? Keep in mind that I would also like to be able to adjust the "thrust" of the rocket on the fly.

Edit: The way I see it, and correct me if I'm wrong, you have two forces (ignoring the main thrust force for now):

1) You have a static "fin" that is always pointed in the same direction as the body. If the body rotates such that the fin is not aligned with the direction of movement, air resistance will apply forces to along the length of the fin, proportional to the angle between the direction of movement and the fin.

2) You have a "rudder", which can rotate freely within a specified range, which is attached some distance from the body's center of mass (in this case we have a circle). Again, when this plane is not parallel to the direction of movement, air resistance causes proportional forces along the length of the rudder.

My question is, differently stated, how do I calculate these proportional forces from air resistance against the fin and rudder?

Edit: For reference, here is some code I wrote to test the accepted answer:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {
        float dc = 0.001f;
        float lc = 0.025f;
        float angle = MathHelper.ToRadians(45);
        Vector2 vel = new Vector2(1, 0);
        Vector2 pos = new Vector2(0, 0);
        for (int i = 0; i < 200; i++)
        {
            Vector2 drag = vel * angle * dc;
            Vector2 sideForce = angle * lc * vel;
            //sideForce = new Vector2(sideForce.Y, -sideForce.X); // rotate 90 degrees CW
            sideForce = new Vector2(-sideForce.Y, sideForce.X); // rotate 90 degrees CCW
            vel = vel + (-drag) + sideForce;
            pos = pos + vel;
            if(i % 10 == 0)
                System.Console.WriteLine("{0}\t{1}\t{2}", pos.X, pos.Y, vel.Length());
        }
    }

When you graph the output of this program, you'll see a nice smooth circular curve, which is exactly what I was looking for!

+2  A: 

I suddenly "get" it.

You want to simulate a rocket powered missile flying in air, OK. That's a different problem than the one I have detailed below, and imposes different limits. You need an aerospace geek. Or you could just punt.


To do it "right" (for space):

The simulated body should be provided with a moment of inertia around its center of mass, and must also have a pointing direction and an angular velocity. Then you compute the angular acceleration from the applied impulse and distance from the CoM, and add that to the angular velocity. This allows you to compute the current "pointing" of the craft (if you don't use gyros or paired attitude jets, you also get a (typically very small) linear acceleration).

To generate a turn, you point the craft off the current direction of movement and apply the main drive.

And if you are serious about this you also need to subtract the mass of burned fuel from the total mass and make the appropriate corrections to the moment of inertia at each time increment.

BTW--This may be more trouble than it is worth: maneuvering a rocket in free-fall is tricky (You may recall that the Russians bungled a docking maneuver at the ISS a few years ago; well, that's not because they are stupid.). Unless you tell us your use case we can't really advise you on that.

A little pseudocode to hint at what you're getting into here:

rocket {
  float structuralMass;
  float fuelMass;
  point position;
  point velocity;
  float heading;
  float omega;       // Angular velocity
  float structuralI; // moment of inertia from craft
  float fuelI;       // moemnt of inertia from the fuel load

  float Mass(){return struturalMass + fuelMass};
  float I(){return struturalI + fuelI};
  float Thrust(float t);
  float AdjustAttitude(float a);
}

The upshot is: maybe you want a "game physics" version.


For reason I won't both to go into here, the most efficient way to run a "real" rocket is generally not to make gradual turns and slow acceleration, but to push hard when ever you want to change direction. In this case you get the angle to thrust by subtracting the desired vector (full vector, not the unit) from the current one. Then you pointing in that direction, and trusting all out until the desired course is reached.

dmckee
It doesn't have to be accurate. It just has to "look good enough". Essentially, the player will control the rudder and thrust with an analog stick. Also, I'm sort of going for a rocket in space, but where space is filled with air. What I'm trying to get at is how to calculate the forces applied to the body which are caused by air resistance on an imaginary "rudder" attached directly to the body's center of mass.
Jeremy Bell
The problem is that "rudder" is entirely the wrong way to think about it. Spaceships do not move that way. They just don't. DO that for a game if you want, but it's not physics.
dmckee
Perhaps a better abstraction might be something like the dynamics of a boat on the surface of the water, as viewed from above?
Jeremy Bell
If it is easier to think of angular velocity and impulses, and a rudder not attached to the center of mass, then I'm fine with that. I thought it might simplify the calculations, but if it doesn't then that's ok.
Jeremy Bell
See edits to original post.
Jeremy Bell
Do you remember the original Asteroids game? That implemented the correct thrust behavior. The turning behavior it supplied is reasonable you gyros instead of thrusters.
dmckee
A: 

Imagine your in floating in empty space... And you have a big rock in your hand... If you throw the rock, a small impulse will be applied to you in the exact opposite direction you throw the rock. You can model your rocket as something that rapidly converts quantum's of fuel into some amount of force (a vector quantity) that you can add to your direction vector.

dicroce
+2  A: 

If you already have code to integrate force and mass to acceleration and velocity, then you just need to calculate the individual part of each of the two elements you're talking about.

Keeping it simple, I'd forget about the fin for a moment and just say that anytime the body of your rocket is at an angle to it's velocity, it will generate a linearly increasing side-force and drag. Just play around with the coefficients until it looks and feels how you want.

Drag = angle*drag_coefficient*velocity + base_drag
SideForce = angle*lift_coefficent*velocity

For the rudder, the effect generated is a moment, but unless your game absolutely needs to go into angular dynamics, the simpler thing to do is let the rudder control put in a fixed amount of change to your rocket body angle per time tick in your game.

Digikata
I'm assuming the side force is rotated 90 degrees, and that base_drag is calculated as some scalar base_drag_coefficient * velocity, is that correct?
Jeremy Bell
Yup, side force is applied 90 degrees to the body orientation, drag is applied negative to the body orientation. For base drag you can set it to a constant or calc as proportional to velocity.
Digikata
Fantastic. This works perfectly. Will edit OP with answer for others to see.
Jeremy Bell