Granjero
Granjero

Reputation: 362

C++ gamedev: truncating float to int

I'm making a game in C++ where is a tank that can moves on a stage. The tank has an angle (float, in degrees, and i'm supposing the tank is at 0º when his cannon points to the right), a speed (float), and there is a time constant called "deltaT" (float).

When the player moves the tank forward, I use trigonometry and the physic equation of position in function of time (I mean X(t), I don't know how it says in English) in order to calculate the new tank's coordinates in the stage.

This is my problem: due to the passage from float to int, the values closest to zero are not taken into account. So, at certain angles, the tank appears rotated, but moves in a different direction.

This is what my code does:

1 - first, I separate the speed in its components X and Y, by using the angle in which the tank is moving:

    float speedX = this->speed * cos(this->angle);
    float speedY = this->speed * sin(this->angle);

2 - then use the equation I mentioned above to get the new coordinates:

    this->x = (int) ceil(this->x + (speedX * deltaT));
    this->y = (int) ceil(this->y - (speedY * deltaT));

The problem begins at the first step: at certain angles, the value of the cos or the sin is very close to zero. So, when I multiply it for speed to obtain, say, speedX, I still got a very low number, and then when I multiply it for deltaT it is still too low, and finally when apply the ceil, that amount is totally lost.

For example, at 94º, with deltaT = 1.5, and speed = 2, and assuming initial value of X is 400, we have:

speedX = -0.1395...
this->x = 400 //it must be 399.86..., but stays in 400 due to the ceiling

So, in my game the tank appears rotated, but moves straight forward. Also, sometimes it moves well backwards but wrong forward, and viceversa.

How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1.

Upvotes: 14

Views: 1230

Answers (3)

Tiger4Hire
Tiger4Hire

Reputation: 1091

Your problem is not accuracy! Floating-point math has 24-bit accuracy, that's plus/minus 1/16,777,216. No problem there.

It's your rounding mode. ceil rounds up.

Try:

int x = this->x + (speedX * deltaT) +.5f;

ceil creates a rounding error (E) of 0<E<1, casting as above gives -.5<E<+.5, which has half the absolute error.

Also, avoid using double math. ceil is the double version, you mean ceilf. Technically, your code casts float->double->int. You gain nothing from this, but it takes time.

And finally... The real problem:

Your accuracy problem really is because you are accumulating it! So 0<E<1 ... PER FRAME!
at 60Hz => 0<E<60*seconds. Thus after a minute 0<E<3600
If X/Y are pixel coordinates, that's a whole screen! No wonder you are struggling.

No matter how you round, this is always going to be a problem. Instead, you to store the floating point result before rounding. Thus the absolute error is always 0<E<1 ... or -.5f < E < .5f for mid-point rounding. Try adding a new floating point position - XPos/YPos

this->XPos += speedX * deltaT;
this->YPos += speedY * deltaT;
this->x = static_cast<int>(this->XPos+.5f);
this->y = static_cast<int>(this->YPos+.5f);

You should now move around smoothly.

PS: The word in English is "parametric", https://en.wikipedia.org/wiki/Parametric_equation

Upvotes: 0

ObscureRobot
ObscureRobot

Reputation: 7336

How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1 :P

You should store your position values as floats, even though they are ultimately used as ints for on-screen positioning. That way, you won't lose the non-integer portion of your position. Just cast to int right at the end when you do your drawing.

Upvotes: 9

David Schwartz
David Schwartz

Reputation: 182769

Keep the location of the tank in floats all the time. Alternatively, only let the tank rotate in increments of 45 degrees. Decide on whether your game will use approximate positions and headings or exact ones and stick to that decision all the way through.

Upvotes: 5

Related Questions