Moving Player Using Sine/Cos

Started by
9 comments, last by GameDev.net 18 years, 8 months ago
Hello everybody, I'm currently facing a mathematical problem. I don't think it's very intense though, that's why I posted here and not in the "Maths & Physics"-Area. I am working on the movement system of a GTA2-clone project at the moment. I have a player struct pretty much defined like this for now: struct player { int x; int y; int angle; int velocity; }; I also coded that pushing UP arrow key increases player.velocity and DOWN decreases it (or makes it negative) and that LEFT decreases the player.angle and RIGHT increases the angle. That works fine. Now I think my mistake is when I calculate the new position of the player. I do it this way at the moment: player.x = player.x + FloatToInt ( IntToFloat ( player.velocity ) * Maths.Sin ( Maths.DegreesToRadians ( IntToFloat ( player.angle ) ) ) ); player.y = player.y + FloatToInt ( IntToFloat ( player.velocity ) * Maths.Cos ( Maths.DegreesToRadians ( IntToFloat ( player.angle ) ) ) ); That results that I can move in only 8 directions. LEFT, RIGHT, UP, DOWN and inbetween those directions. My guess that this is because of a rounding error with FloatToInt, but what should I change in order to be able to walk in 360 degrees (pretty much like it is in GTA2)? Thanks for your help, Jan.
Advertisement
Try changing your variables to doubles or floats:

struct player{double x;double y;double angle;double velocity;};


then in order to move the player

player.x += sin(player.angle/57.3)*player.velocity
player.y += cos(player.angle/57.3)*player.velocity

then, whenever you are drawing him on screen and you need to have the variables as an int just cast them:

DrawThing((int)player.x , (int)player.y);

I'm sure there's better ways to do this, but thats how I do it and it works.
My Current Project Angels 22 (4E5)
You might also want to multiply the velocity change (acceleration) by the time delta, and the velocity itself by the time delta again, if you're not doing fixed time steps. Also, do not use integer variables to represent vectors; the precision problems will be horrendous. Unless your target platform has some very weird requirements I would at least revise an object's position tracking structure to:

struct vector_2d{    float x;    float y;};struct physics_object{    vector_2d position;    vector_2d velocity;    float angle;};


Keep your angle separated from your velocity as how the car is turned should be independent from its velocity. Consider to also add a z vector component even if your game is in 2D as you might want to track heights nontheless: Cars that can leave the ground driving off high edges, for bullets, and similar stuff.

EDIT: As Sir Sapo said, using floats (or doubles if you need more precision), will not influence your drawing negatively. Just convert each float to an integer like he showed, though you may or may not want to round the floats by making it int(float_number + 0.5f) instead.

EDIT2: When updating any object, you can do this (assuming 2D):

//dt is delta time, or time since last frame//acceleration is a scalar quantity, you can make this by summing forces and using the formula a = F / mplayer.velocity.x += cos(angle) * acceleration * dt;player.velocity.y += sin(angle) * acceleration * dt;player.position.x += player.velocity.x * dt;player.position.y += player.velocity.y * dt;
Hmm... I changed it, but it now placed the player object somewhere offscreen.

This is what I have:


struct player
{
float x; // the x-coordinate of the player
float y; // the y-coordinate of the player
float angle; // the angle of the player
float velocity; // the velocity ( thrust ) of the player
};
[\CODE]


player.x += Maths.Sin ( player.angle / 57.3 ) * player.velocity;
player.y += Maths.Cos ( player.angle / 57.3 ) * player.velocity;
[\CODE]

And then I use those player.x and player.y values, cast them to ints and draw the player.

What's wrong?

Oh, and player.velocity is 0 when no key is pressed. Those values work and are correct (so it's not that I wouldn't initialize the angle or especially velocity properly)...

One reason why the player is placed offscren may be the following:

Your function which modifies positions and or velocities triggers way too many times each second. Either multiply by delta time like I showed or limit the possible number of updates.

Either that, or your drawing function does not convert to ints properly.

Do you see the player before you move him or not? I mean, if he has zero velocity, do you still see him at screen?

EDIT: Just to remember, make velocity a vector and separate from the car's angle. It's very nice to have a car that's able to move in another direction than it's currently facing. :)
But how can updating this function often displace the player? Shouldn't it just become more accurate?

I am sorry for being a little newbie here, thanks for your patience.

Also, I am rather sure the cast is working.

I can't store vectors how you supposed since the platform does not support structs in structs at the moment.

EDIT: Sorry, saw your edits just by now. I don't see him at all moving around. My frame rate is at max fixed value 40... Thanks for your answers though. Keep em comming if there's any ideas out there to fix this.
The function becomes more accurate if you have an accurate time measurement function. Also, if you don't multiply by the time since the last update, consider what happens:

CASE 1:

UpdatePlayer() moves player at 10 velocity units.
It triggers 100 times each second.
The total displacement is 100 * 10 = 1000 velocity units!

If you multiply by the delta time which is 1 / number of updates per second you get the following:

CASE 2:

Delta_time = 1 / 100 = 0.01.
UpdatePlayer(Delta_time) moves the player 10 * 0.01 = 0.1 velocity units.
It triggers 100 times each second.
The total displacement is 100 * 0.1 = 10 velocity units! (As you probably intended.)

EDIT: Saw your frame limit to be 40, then use 40 instead of 100 in example... However, it may still be a good idea to measure time since limiting frame rate does not always work perfectly... If you don't however you can just adjust your velocities by a factor of (1 / 40) to get it working provided it really triggers not much from 40 times a second.
Ah, I see.

Now I just need a good way to calcualte that delta_t using my platform...

I will post once I have it included.


Thanks though.
If you have any sort of time function with high precision it's enough to take the time of the current frame minus that of the last. If it doesn't have as high precision you can measure across several frames and divide by the number of them to get the average frame time.
Hmm... I can get the current framerate. And that's pretty much about it, I believe. I mean I have a timer system, which I could use. But how exactly?

EDIT: Nevermind, got it to work. Works accurately and fine even without delta time.

This topic is closed to new replies.

Advertisement