C++ gamedev:将 float 截断为 int

发布于 2024-12-12 22:36:59 字数 1065 浏览 2 评论 0 原文

我正在用 C++ 制作一个游戏,其中有一辆可以在舞台上移动的坦克。坦克有一个角度(浮动,以度为单位,我假设当他的大炮指向右侧时坦克处于 0°),速度(浮动),并且有一个称为“deltaT”(浮动)的时间常数。

当玩家向前移动坦克时,我使用三角学和时间函数位置的物理方程(我的意思是 X(t),我不知道它用英语怎么说)来计算新坦克在阶段。

这是我的问题:由于从 float 到 int 的转变,最接近零的值不被考虑在内。因此,在某些角度下,坦克会出现旋转,但会朝不同的方向移动。

这就是我的代码所做的:

1 - 首先,我通过使用坦克移动的角度来分离其分量 X 和 Y 中的速度:

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

2 - 然后使用我上面提到的方程来获取新坐标:

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

问题从第一步开始:在某些角度,cos 或 sin 的值非常接近于零。 因此,当我将其乘以速度以获得速度X时,我仍然得到一个非常低的数字,然后当我将其乘以deltaT时,它仍然太低,最后当应用ceil时,该数量完全丢失。

例如,在 94° 处,deltaT = 1.5,速度 = 2,并假设 X 的初始值为 400,我们有:

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

因此,在我的游戏中,坦克看起来是旋转的,但直线向前移动。而且,有时它向后移动得很好,但向前移动却错误,反之亦然。

怎样做才能让坦克的方向更加准确呢?提高速度或 deltaT 值不是选择,因为它是关于坦克,而不是公式 1。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

丢了幸福的猪 2024-12-19 22:36:59

如何才能让坦克的方向更加准确?提高速度或 deltaT 的值不是选项,因为它是关于坦克,而不是公式 1 :P

您应该将位置值存储为 float,即使它们最终用作 int 用于屏幕定位。这样,您就不会失去头寸的非整数部分。当你进行绘图时,只需在最后强制转换为 int 即可。

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.

半边脸i 2024-12-19 22:36:59

始终将水箱的位置保持在 float 中。或者,仅让水箱以 45 度的增量旋转。决定您的游戏是使用近似位置和标题还是精确位置和标题,并始终坚持该决定。

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.

思慕 2024-12-19 22:36:59

你的问题不是准确性!浮点数学具有 24 位精度,即正/负 1/16,777,216。那里没问题。

这是您的舍入模式
ceil 向上舍入。

尝试:

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

ceil 创建 0

另外,避免使用双重数学。 ceil 是双版本,您的意思是 ceilf。从技术上讲,您的代码会强制转换 float->double->int。你不会从中得到任何好处,但这需要时间。

最后......真正的问题:

你的准确性问题确实是因为你正在积累它!
所以 0
60Hz 时 => 0<E<60*秒。因此一分钟后 0 如果 X/Y 是像素坐标,那就是整个屏幕!难怪你在挣扎。

无论你如何处理,这始终是一个问题。
相反,您应在舍入之前存储浮点结果。因此,绝对误差始终为 0

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

您现在应该可以顺利移动。

PS:英文单词是“parametric”,https://en.wikipedia.org/wiki/Parametric_equation

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文