Moving in the direction of rotation?

Started by
23 comments, last by Carbon101 10 years, 4 months ago

Ok here we go:

Imagine you have a ship with a position and a speed


class Ship
{
public:
     vec2 position;
     vec2 direction;
     vec2 velocity;
}
Ship ship;

Ignoring the bad OO setup, we now want to rotate the ship, and the move the ship.
// Rotate vector by an angle
// remember to either create a new vector by doing this, or make a copy of the old one, as you require both x and y
ship.direction = vec2(cos(angle) * ship.direction.x - sin(angle) * ship.direction.y,
                      sin(angle) * ship.direction.x + cos(angle) * ship.direction.y);
// .. and we don't need to normalize, because cos() and sin() already makes it unit length 1

// If we are using the ships engines, we are adding thrust
// Add speed towards the direction the ship is facing
float thrust = 0.1f;
ship.velocity += ship.direction * thrust;

// And move the ship by its constant velocity each 'tick'
ship.position += ship.velocity;

// Let's check if our round ship is too close to a round object
float ship_radius = 2.0f;
float object_radius = 2.0f;

// create new vector which we will be measuring the length off of
// another method is to use an existing distance() function from a library
float dist = (ship.position - object.position).length();
// or..
float dist = distance(ship.position, object.position);

if (dist < ship_radius + object_radius)
{
    // the ship is too close to the object
    // here we can calculate a tangent and bounce the ship if we wanted too
}

I just wrote that up, so there may be errors

It's also not the best way to rotate a ship, admittedly. It works though!

Edited to fix some issues.

Advertisement

vec2 speed;

The vector is called `velocity'; `speed' is the length of the velocity.

Ignoring the bad OO setup, we now want to rotate the ship, and the move the ship.
// To rotate by an angle, first get old angle
old_angle = atan2(direction.y, direction.x);
// Add new angle
ship.direction.x = cos(angle + old_angle);
ship.direction.y = sin(angle + old_angle);
// .. and we don't need to normalize, because cos() and sin() already makes it unit length 1

That is pretty awful. That's the method I came up to do rotations when I was 11. I think it was OK as a first effort by a kid, but it's ridiculously wasteful.

This is much more reasonable:

  rotated.x = cos(angle) * original.x - sin(angle) * original.y;
  rotated.y = sin(angle) * original.x + cos(angle) * original.y;

And you should probably encode the rotation as (cos(angle), sin(angle)) instead of just the angle. In that case applying a rotation is four products and two additions, instead of the really expensive calls to atan2(), sin() and cos().

If you represent (x, y) by the complex number (x + y*i), the formula is simply

  rotated = original * (cos(angle) + sin(angle) * i)

And if your rotation was already stored as a unit-length complex number, it would simply be

  rotated = original * rotation;

// Let's check if our round ship is too close to a round object
float ship_radius = 2.0f;
float object_radius = 2.0f;

// create new vector which we will be measuring the length off of
// another method is to use an existing distance() function from a library
float dist = (ship.position - object.position).length();
// or..
float dist = distance(ship.position, object.position);

if (dist < ship_radius + object_radius)
{
// the ship is too close to the object
// here we can calculate a tangent and bounce the ship if we wanted too
}

You should compute the square of the distance and compare that to the square of the sum of the radii. That way you avoid computing an expensive square root.

Some things to think about in addition to Alvaro's good points:

You should probably cap the ship's Velocity, or it's going to get going uncontrollably fast. (The easiest way is to check the length of the velocity vector, if it's over some maximum value, then normalize your velocity vector and multiply it by the maximum value)

You should probably decay the ship's Velocity, so it will slow down when not receiving any thrust. (If you're not doing true space physics) Easiest way is to just take the current velocity and multiply it by some number less than 1, like 0.9 or something. Play with a value til you get one you like.

Depending on the max velocity, you may want to do a more complicated form of collision, if you're moving fast enough and the other object's radius is small enough, you'll move 'through' it.

EDIT: And you should probably have a delta time in your calculations as well, or you'll get different behavior depending on how fast the computer running the program is.

I didn't know the rotation thing, actually. Speed was a mistake (, I know better).

Many thanks for the pointers, it was meant as a good basis to get something moving and rotating on the screen. smile.png

So, no delta and no velocity caps. tongue.png

I will edit. (I did not end up optimizing the distance_squared thing, simply because the concept is most important.)

Turns out I was on the right course on the first couple of attempts. My problem was really an image issue not a mathematical one. Lol

Thank you everybody for all your input. Each one of your responses was insightful and I appreciate your thoughtful responses.

This topic is closed to new replies.

Advertisement