首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >让计算机实现360度=0度,旋转炮塔

让计算机实现360度=0度,旋转炮塔
EN

Stack Overflow用户
提问于 2009-06-26 12:47:18
回答 14查看 11K关注 0票数 19

我在做一个游戏,里面有一个电脑控制的炮塔。炮塔可以360度旋转。

它使用trig来找出瞄准枪所需的角度(objdeg),并将当前枪的角度存储在(Objdeg)中。

下面的代码以设定的速度旋转喷枪

代码语言:javascript
复制
if (objdeg > gundeg)
{
    gundeg++;
}
if (objdeg < gundeg)
{
    gundeg--;
}

问题是,如果有一个物体在10度,枪旋转,射击并摧毁它,如果另一个目标出现在320度,枪将逆时针旋转310度,而不是仅仅顺时针旋转60度来击中它。

我怎样才能修复我的代码,使它不会愚蠢地运行?

EN

回答 14

Stack Overflow用户

回答已采纳

发布于 2009-06-26 13:00:41

如果需要在一个方向上旋转180度以上才能对准炮塔,则旋转另一个方向会更快。

我只需要检查一下,然后按适当的方向旋转

代码语言:javascript
复制
if (objdeg != gundeg)
{
    if ((gundeg - objdeg) > 180)
       gundeg++;
    else
       gundeg--;
}

编辑:新解决方案

我已经根据评论中的反馈改进了我的解决方案。这决定了目标是在炮塔的“左边还是右边”,并决定转向哪个方向。如果目标距离超过180度,它就会反转这个方向。

代码语言:javascript
复制
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;
 }
票数 20
EN

Stack Overflow用户

发布于 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,它会走更短的路。

代码语言:javascript
复制
#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;
}
票数 25
EN

Stack Overflow用户

发布于 2009-06-26 12:52:21

归一化为[0,360]:

(即半开放范围)

使用模运算符执行"get除法余数“:

代码语言:javascript
复制
361 % 360

将为1。

在C/C++/...样式语言这应该是

代码语言:javascript
复制
gundeg %= 360

注意(感谢评论):如果gundeg是一个浮点类型,你需要在C/C++:fmod中使用库函数,或者自己做(.NET):

代码语言:javascript
复制
double FMod(double a, double b) {
  return a - Math.floor(a / b) * b;
}

转向哪条路?

在C#中,假设方向是逆时针测量的,那么哪条路更短(如果转弯是180°,那么答案是任意的)

代码语言:javascript
复制
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)。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1048945

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档