我在做一个游戏,里面有一个电脑控制的炮塔。炮塔可以360度旋转。
它使用trig来找出瞄准枪所需的角度(objdeg),并将当前枪的角度存储在(Objdeg)中。
下面的代码以设定的速度旋转喷枪
if (objdeg > gundeg)
{
gundeg++;
}
if (objdeg < gundeg)
{
gundeg--;
}问题是,如果有一个物体在10度,枪旋转,射击并摧毁它,如果另一个目标出现在320度,枪将逆时针旋转310度,而不是仅仅顺时针旋转60度来击中它。
我怎样才能修复我的代码,使它不会愚蠢地运行?
发布于 2009-06-26 13:00:41
如果需要在一个方向上旋转180度以上才能对准炮塔,则旋转另一个方向会更快。
我只需要检查一下,然后按适当的方向旋转
if (objdeg != gundeg)
{
if ((gundeg - objdeg) > 180)
gundeg++;
else
gundeg--;
}编辑:新解决方案
我已经根据评论中的反馈改进了我的解决方案。这决定了目标是在炮塔的“左边还是右边”,并决定转向哪个方向。如果目标距离超过180度,它就会反转这个方向。
if (objdeg != gundeg)
{
int change = 0;
int diff = (gundeg - objdeg)%360;
if (diff < 0)
change = 1;
else
change = -1;
if (Math.Abs(diff) > 180)
change = 0 - change;
gundeg += change;
}发布于 2009-06-26 13:52:52
如果你用BAMS来表示你的角度,你可以完全避免除法(和mod),BAMS代表二进制角度测量系统。其思想是,如果将角度存储在N位整数中,则使用该整数的整个范围来表示角度。这样,就不需要担心溢出超过360,因为表示的自然模-2^N属性会为您处理它。
例如,假设您使用8位。这会将你的圆圈分成256个可能的方向。(您可以选择更多位,但为了示例起见,8位比较方便)。设0x00代表0度,0x40代表90度,0x80代表180度,0xC0代表270度。不要担心“符号”这一点,BAMS对于角度来说是很自然的。如果您将0xC0解释为“无符号”并缩放到360/256度,则角度为(+192)(360/256) = +270;但如果将0xC0解释为“有符号”,则角度为(-64)(360/256)= -90。请注意,-90和+270在角度方面表示相同的东西。
如果要将三角函数应用于BAMS角度,可以预先计算表格。有一些技巧可以缩小表的大小,但您可以看到表并不都那么大。要为8位BAMS存储一个完整的双精度正弦表和余弦表,只需占用不超过4K的内存。
既然您提到在游戏中使用它,那么您可能可以使用8位或10位表示法。无论何时添加或减去角度,都可以使用逻辑与运算将结果强制转换为N位,例如,8位的角度&= 0x00FF。
忘记了最好的部分(编辑)
在BAMS系统中,右转与左转的问题很容易解决。只需取差值,并确保只保留N个有意义的位。将MSB解释为符号位表明您应该转向哪个方向。如果差值为负,则通过差值的abs()转到相反的方向。
这个丑陋的小C程序演示了。首先试着给它输入20 10和20 30。然后尝试通过绕过零点来欺骗它。给它20 -10,它就会左转。给它20 350,它仍然向左转。请注意,因为它是在8位内完成的,所以181和180是无法区分的,所以如果你输入20 201,它转向右而不是左-在8位提供的分辨率下,在这种情况下左转和右转是相同的。输入20205,它会走更短的路。
#include <stdio.h>
#include <math.h>
#define TOBAMS(x) (((x)/360.0) * 256)
#define TODEGS(b) (((b)/256.0) * 360)
int main(void)
{
double a1, a2; // "real" angles
int b1, b2, b3; // BAMS angles
// get some input
printf("Start Angle ? ");
scanf("%lf", &a1);
printf("Goal Angle ? ");
scanf("%lf", &a2);
b1 = TOBAMS(a1);
b2 = TOBAMS(a2);
// difference increases with increasing goal angle
// difference decreases with increasing start angle
b3 = b2 - b1;
b3 &= 0xff;
printf("Start at %7.2lf deg and go to %7.2lf deg\n", a1, a2);
printf("BAMS are 0x%02X and 0x%02X\n", b1, b2);
printf("BAMS diff is 0x%02X\n", b3);
// check what would be the 'sign bit' of the difference
// negative (msb set) means turn one way, positive the other
if( b3 & 0x80 )
{
// difference is negative; negate to recover the
// DISTANCE to move, since the negative-ness just
// indicates direction.
// cheap 2's complement on an N-bit value:
// invert, increment, trim
b3 ^= -1; // XOR -1 inverts all the bits
b3 += 1; // "add 1 to x" :P
b3 &= 0xFF; // retain only N bits
// difference is already positive, can just use it
printf("Turn left %lf degrees\n", TODEGS(b3));
printf("Turn left %d counts\n", b3);
}
else
{
printf("Turn right %lf degrees\n", TODEGS(b3));
printf("Turn right %d counts\n", b3);
}
return 0;
}发布于 2009-06-26 12:52:21
归一化为[0,360]:
(即半开放范围)
使用模运算符执行"get除法余数“:
361 % 360将为1。
在C/C++/...样式语言这应该是
gundeg %= 360注意(感谢评论):如果gundeg是一个浮点类型,你需要在C/C++:fmod中使用库函数,或者自己做(.NET):
double FMod(double a, double b) {
return a - Math.floor(a / b) * b;
}转向哪条路?
在C#中,假设方向是逆时针测量的,那么哪条路更短(如果转弯是180°,那么答案是任意的)
TurnDirection WhichWayToTurn(double currentDirection, double targetDirection) {
Debug.Assert(currentDirection >= 0.0 && currentDirection < 360.0
&& targetDirection >= 0.0 && targetDirection < 360.0);
var diff = targetDirection - currentDirection ;
if (Math.Abs(diff) <= FloatEpsilon) {
return TurnDirection.None;
} else if (diff > 0.0) {
return TurnDirection.AntiClockwise;
} else {
return TurnDirection.Clockwise;
}
}NB。这需要测试。
注意使用assert来确认归一化角度的前提条件,我使用assert,因为这是一个内部函数,不应该接收未经验证的数据。如果这是一个通常可重用的函数,那么参数检查应该抛出异常或返回错误(取决于语言)。
另请注意。要解决这样的问题,没有什么比铅笔和纸更好的了(我最初的版本是错误的,因为我混淆了(-180,180]和[0,360)。
https://stackoverflow.com/questions/1048945
复制相似问题