Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vectors, calculate movement forces with max speed

Im building a small space shooter game. I have how ever stubbed on a math problem when it come to the space physics.

Describing this with words is following: There is a max speed. So if you give full full speed you ship will move with this over the screen over and over again like in the old asteroids games. If then release the rocket boost you ship should be keep moving with that speed over the screen.

Then the tricky part where Im stuck right now.

If you rotate the ship ANY angle and gives boost again the ship should try to get to this direction and NEVER surpas the max speed when it comes to how fast it is moving. so my question is. anyone have a good idea formula for this issue? feels like it has been done before if you know what to look for. :)

Ill add this small image to illustrate what is tried to be done with some vector calculations. Max speed movement with force

Red ring: Max speed

Green line: current ship direction.

Black line: direction(s) and how fast the ship is moveing in x and y.

Black ring: origin of movement.

Can illustrate it but hard to find a good math solution for this. :)

EDIT

This is the code Im using right now in every frame. It gives movement to the ship but does not give the force of movement the user has to counter-react with its rocket boosters to get the ship to stop or slow down. With this it stops the instant you release the accelerating speed for the ship.

    //Calculates ship movement rules
var shipVelocityVec = GetVectorPosByAngle(shipMoveSpeed, shipRotationAngle);
var shipUnitVec =$V([Math.cos(shipRotationAngle),Math.sin(shipRotationAngle),0]);
var rawAccel = shipAccelSpeed / shipMass;
var scale = (shipUnitVec.dot(shipVelocityVec))/(shipTopSpeed * shipTopSpeed);
var v1 = shipUnitVec.subtract(shipVelocityVec.multiply(scale));
var finalAccelVec = v1.multiply(rawAccel);
console.log(finalAccelVec);

//move ship according to rules
var shipPosVector = $V([shipxPos, shipyPos, 0]);
var movementVector =  shipPosVector.add(finalAccelVec);
shipxPos = movementVector.elements[0];
shipyPos = movementVector.elements[1];

To give the acceleration speed the user has to keep the button pressed. the instance the user releases the button the acceleration is set to zero and have to boost over again to give maximum acceleration throttle.

Solution found! Posted it here how it was done.

like image 278
Jonas Lindahl Avatar asked Feb 15 '12 14:02

Jonas Lindahl


People also ask

How do you convert speed into force?

Speed is a measure of distance per unit of time, and force measures acceleration times mass. To convert speed to force, you need to convert the speed to acceleration by dividing the change in speed by time. This gives you acceleration. Then, you must multiply by the mass to get force.


3 Answers

You seem to be confusing something - there is no issue capping the velocity to a maximum speed, even when the acceleration is at a different angle, if you are using vectors correctly.

Your setup should look something like this:

  1. Your ship should have a position, a velocity, and an acceleration. Each of these can be represented as a 2D vector (with separate x and y components).
  2. Every frame, add the velocity to the position, and the acceleration to the velocity.
  3. Every frame, check that the speed does not exceed some maximum. If it does, cap the speed by normalizing the velocity vector and multiplying it by the max speed.

That's it! There are no special cases to consider - that's the magic of vector algebra!

like image 75
BlueRaja - Danny Pflughoeft Avatar answered Oct 08 '22 14:10

BlueRaja - Danny Pflughoeft


@BlueRaja's solution should work, although you will get an abrupt change in behavior when you hit the max speed.

If you want a solution with no "seams", I believe you can do what you're looking for by adding the right kind of adjustment to the acceleration, as follows:

ship_unit_vec = [cos(ship_angle), sin(ship_angle)]
raw_accel = (engine_thrust / ship_mass)

scale = dot_product(ship_unit_vec, ship_velocity_vec) / max_speed^2

final_accel_vec = raw_accel * (ship_unit_vec - scale * ship_velocity_vec)

Notes:

  • If |ship_velocity_vec|<<max_speed, the scale * ship_velocity_vec component is negligable.
  • If |ship_velocity_vec|==max_speed, the scale * ship_velocity_vec component cancels all additional acceleration in the "wrong" direction, and aids acceleration in the "right" direction.
  • I've never tried this out, so I don't know how it will feel to the player...

More generally, if there are more sources of acceleration than just the ship thrusters, you can add them all together (say, as raw_accel_vec), and perform the above operation all at once:

scale_forall = dot_product(raw_accel_vec, ship_velocity_vec) / max_speed^2
final_accel_vec = raw_accel_vec - scale_forall * ship_velocity_vec
like image 26
comingstorm Avatar answered Oct 08 '22 15:10

comingstorm


Rather than just imposing an ad hoc maximum speed, you could use some actual physics and impose a drag force. This would be an extra force acting on the spaceship, directed opposite to the velocity vector. For the magnitude of the drag force, it's simplest to just take it proportional to the velocity vector.

The overall effect is that the drag force increases as the spaceship moves faster, making it harder to accelerate in the direction of motion when the ship moves faster. It also makes acceleration easier when it is opposed to the direction of motion.

One point where this diverges from your description is that the spaceship won't continue at maximum speed forever, it will slow down. It won't, however, come to a halt, since the drag force drops as the ship slows down. That matches my memory of asteroids better than the ship continuing forever at constant velocity, but it has been quite a while since I've played.

like image 1
Michael J. Barber Avatar answered Oct 08 '22 16:10

Michael J. Barber