我正在用 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.
发布评论
评论(3)
您应该将位置值存储为
float
,即使它们最终用作int
用于屏幕定位。这样,您就不会失去头寸的非整数部分。当你进行绘图时,只需在最后强制转换为int
即可。You should store your position values as
float
s, even though they are ultimately used asint
s for on-screen positioning. That way, you won't lose the non-integer portion of your position. Just cast toint
right at the end when you do your drawing.始终将水箱的位置保持在
float
中。或者,仅让水箱以 45 度的增量旋转。决定您的游戏是使用近似位置和标题还是精确位置和标题,并始终坚持该决定。Keep the location of the tank in
float
s 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.你的问题不是准确性!浮点数学具有 24 位精度,即正/负 1/16,777,216。那里没问题。
这是您的舍入模式。
ceil
向上舍入。尝试:
ceil
创建 0另外,避免使用双重数学。
ceil
是双版本,您的意思是ceilf
。从技术上讲,您的代码会强制转换 float->double->int。你不会从中得到任何好处,但这需要时间。最后......真正的问题:
你的准确性问题确实是因为你正在积累它!
如果 X/Y 是像素坐标,那就是整个屏幕!难怪你在挣扎。
所以 0
60Hz 时 => 0<E<60*秒。因此一分钟后 0
无论你如何处理,这始终是一个问题。
相反,您应在舍入之前存储浮点结果。因此,绝对误差始终为 0
您现在应该可以顺利移动。
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:
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 meanceilf
. 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
You should now move around smoothly.
PS: The word in English is "parametric", https://en.wikipedia.org/wiki/Parametric_equation