Archived

This topic is now archived and is closed to further replies.

B-Barlow

2D accelleration/rotation math (Asteroids style)

Recommended Posts

It''s been about three decades since I even glanced at any trig-calculus material, so I was wondering if I could get a little help. I''m working on a simple 2D Asteroids/Star Control type game. What I need to know is what the calculations are for determining the X,Y offset per timer tick. I have my ship''s maximum velocity, it''s current movement direction (XVelocity and YVelocity), the direction the ship is pointing in degrees, and an accelleration value. Now I just need to know what to do with ''em I need to know how to determine the new XVelocity and YVelocity values when accelerating. Any help would be greatly appreciated.

Share this post


Link to post
Share on other sites
quote:
Original post by Vlion
newxval = oldxval+accelxval;


WOW! Gee thanks!

Maybe I just didn't make myself clear. If I accellerate at a 45 degree angle to both axis using that math my actual velocity will exceed my specified maximum velocity as I would then be traveling at the maximum velocity along both axis: sqrt( MaxVelocity^2 + MaxVelocity^2 ).

Perhaps Asteroids is a bad example. Think Star Control if you've played it. It works basically like asteroids, but if you accellerate along the X axis then turn 90 degrees and accellerate along the Y axis, your movement along the X axis will decrease until you will eventually end up only moving along the Y axis and you will never exceed the maximum velocity.


Edited by - B-Barlow on January 1, 2002 3:59:24 AM

Share this post


Link to post
Share on other sites
No, you add the acceleration vector to the velocity vector. Acceleration has both a magnitude and direction. If you acceleration is a constant, a, then the velocity at time t is a*t+v0 where v0 is the velocity at time zero. The position at time t is 1/2*a*t^2+v0*t+p0 where p0 is the position at time zero. In 1D those are 1D vectors or in other words scalars. In 2D and 3D those are 2D and 3D vectors. The differance in velocity from t to t+dt is a*(t+dt)+v0-(a*t+v0) or a*t+a*dt+v0-a*t-v0 or a*dt. So if you add a*dt to the previous velocity you get the new velocity after dt more whatever time units you are using. If you have a fixed frame interval then you can use that interval length for your time basis so dt is 1.

One thing to note is that under accelerated motion your velocity is constantly changing. You move the average velocity times the time, not the ending velocity times the time. So it is 1/2*(v1+v2)*dt with constant acceleration. Using the equation above the differance in position from t to t+dt is 1/2*a*(t+dt)^2+v0*(t+dt)+p0-(1/2*a*t^2+v0*t+po) or a*t*dt+1/2*a*dt^2+v0*dt or dt*(1/2*a*dt+(a*t+v0)), but a*t+v0 is the velocity at the start of the frame, v1, and a*dt is the change in velocity, dv, during the frame. So the change in position is dt*(1/2*dv+v1). If you call the velocity at the end of the frame v2 then that can be rewriten as dt*(1/2*(v2-v1)+v1) which can be rewriten as 1/2*(v1+v2)*dt.

You apply your max velocity by simply adding an if after calculating the velocity at the end of the frame. If it is greater than the maximum velocity then you set it to the maximum velocity. To be completely accurate you would have to calculate when within the frame you hit the maximum velocity, calculate the displacement up to that time and then the additional displacement to the end of the frame. It isn''t an accurate model to start with and even if it was the tiny differance in position over such a short interval isn''t worth worrying about. The maximum error is 1/2*dv*dt which most likely is not even a pixel so your user is not going to notice.

Share this post


Link to post
Share on other sites
quote:
Original post by LilBudyWizer
No, you add the acceleration vector to the velocity vector. Acceleration has both a magnitude and direction. If you acceleration is a constant, a, then the velocity at time t is a*t+v0 where v0 is the velocity at time zero. The position at time t is 1/2*a*t^2+v0*t+p0 where p0 is the position at time zero. In 1D those are 1D vectors or in other words scalars. In 2D and 3D those are 2D and 3D vectors. The differance in velocity from t to t+dt is a*(t+dt)+v0-(a*t+v0) or a*t+a*dt+v0-a*t-v0 or a*dt. So if you add a*dt to the previous velocity you get the new velocity after dt more whatever time units you are using. If you have a fixed frame interval then you can use that interval length for your time basis so dt is 1.

One thing to note is that under accelerated motion your velocity is constantly changing. You move the average velocity times the time, not the ending velocity times the time. So it is 1/2*(v1+v2)*dt with constant acceleration. Using the equation above the differance in position from t to t+dt is 1/2*a*(t+dt)^2+v0*(t+dt)+p0-(1/2*a*t^2+v0*t+po) or a*t*dt+1/2*a*dt^2+v0*dt or dt*(1/2*a*dt+(a*t+v0)), but a*t+v0 is the velocity at the start of the frame, v1, and a*dt is the change in velocity, dv, during the frame. So the change in position is dt*(1/2*dv+v1). If you call the velocity at the end of the frame v2 then that can be rewriten as dt*(1/2*(v2-v1)+v1) which can be rewriten as 1/2*(v1+v2)*dt.

You apply your max velocity by simply adding an if after calculating the velocity at the end of the frame. If it is greater than the maximum velocity then you set it to the maximum velocity. To be completely accurate you would have to calculate when within the frame you hit the maximum velocity, calculate the displacement up to that time and then the additional displacement to the end of the frame. It isn''t an accurate model to start with and even if it was the tiny differance in position over such a short interval isn''t worth worrying about. The maximum error is 1/2*dv*dt which most likely is not even a pixel so your user is not going to notice.


Thanks That sounds like what I needed to know and I can probably make it work now. Unfortunately I haven''t dealt with vecor math since high school. Know of any good books and/or online tutorials on this anywhere geared toward people who barely remember basic algebra?

Share this post


Link to post
Share on other sites
      

// This ought to give you the basic idea.

// The keydown(...) function is of course not real.

// Also, remember that all angles are in radians.



#include <math.h>

struct vector
{
float x, y;
};

struct point
{
float x, y;
};

struct spaceship
{
vector velocity;
point coord;
float angle;
}

int main()
{

spaceship player; memset(&player, 0, sizeof(spaceship));

for(bool exit = false; !exit; ) //Simple game loop

{
if(keydown(LEFT))
player.angle -= ROTATION_SPEED;
if(keydown(RIGHT))
player.angle += ROTATION_SPEED;
if(keydown(UP))
{
player.velocity.x += sinf(angle) * THRUSTER_FORCE;
player.velocity.y += cosf(angle) * THRUSTER_FORCE;
}
if(keydown(DOWN))
{
player.velocity.x -= sinf(angle) * THRUSTER_FORCE;
player.velocity.y -= cosf(angle) * THRUSTER_FORCE;
}

player.coord.x += player.velocity.x;
player.coord.y += player.velocity.y;
}

return 0;
}



Edited by - TerranFury on January 1, 2002 2:21:33 PM

Share this post


Link to post
Share on other sites
I guess that would be close enough on a small interval which it is. Generally you use cosine for x and sine for y though. Switching them makes zero degrees in the positive y direction and 90 degree in the positive x direction. You would check sinf(angle) * MAX_VELOCITY and cosf(angle) * MAX_VELOCITY against player.velocity.x and player.velocity.y respectively and use the smaller of the two.

Share this post


Link to post
Share on other sites
Thanks guys I''m almost there.

Just one thing though. Using the following code, if you accelerate along the x axis to max speed then turn 90 degrees and accelerate you come to an abrupt halt along the x axis.

  
m_MaxVelocity = 2.0f;
m_Acceleration = 0.02f;

m_XVelocity += (cosf(m_Angle * 3.14159f / 180 ) * m_Acceleration);
m_YVelocity += (sinf(m_Angle * 3.14159f / 180 ) * m_Acceleration);

if( m_XVelocity > 0 )
{
if( m_XVelocity > (cosf(m_Angle * 3.14159f / 180) * m_MaxVelocity) )
m_XVelocity = (cosf(m_Angle * 3.14159f / 180) * m_MaxVelocity);
}
else
{
if( m_XVelocity < (cosf(m_Angle * 3.14159f / 180) * m_MaxVelocity) )
m_XVelocity = (cosf(m_Angle * 3.14159f / 180) * m_MaxVelocity);
}

if( m_YVelocity > 0 )
{
if( m_YVelocity > (sinf(m_Angle * 3.14159f / 180) * m_MaxVelocity) )
m_YVelocity = (sinf(m_Angle * 3.14159f / 180) * m_MaxVelocity);
}
else
{
if( m_YVelocity < (sinf(m_Angle * 3.14159f / 180) * m_MaxVelocity) )
m_YVelocity = (sinf(m_Angle * 3.14159f / 180) * m_MaxVelocity);
}



Share this post


Link to post
Share on other sites
Sorry, my mistake. Try:

  
m_MagVelocity = sqrt(m_XVelocity*m_XVelocity+m_YVelocity*m_YVelocity);
if (m_MagVelocity>m_MaxVelocity)
{
m_XVelocity = m_XVelocity * m_MaxVelocity / m_MagVelocity;
m_YVelocity = m_YVelocity * m_MaxVelocity / m_MagVelocity;
}


The m_MagVelocity is the magnitude of the velocity vector. The magnitude of a vector is it''s length and in the case of a velocity vector it is the speed. I was just thinking of capping the speed on a straight line path.

Share this post


Link to post
Share on other sites