确定是从两个角度顺时针或逆时针转动

Guy*_*ito 3 .net c# math xna angle

我在XNA制作游戏.我有敌人和球员.敌人应该逐渐转向玩家.他们应该确定是否需要顺时针或逆时针转动,以较短者为准.

通过使用Atan2,我得到了敌人当前面对的角度和它应该面对的角度(敌人和玩家之间的线的角度)作为弧度.

我虽然得到了一些奇怪的行为.让我们在下面的场景中说.敌人可能会朝错误的方向转过来.

在此输入图像描述

我的代码(下面)不断变长,我仍然遇到问题.此代码是敌人类Update方法的一部分.这必须是游戏中需要克服的常见问题.有没有办法解决这个问题?

            //this bit is just in case enemy has rotated more than 360 degrees (gets set back to 0)
            if (Math.Abs(_blocklist[0]._floor.Revolutions) >= 2)
            {
                _blocklist[0]._floor.Rotation = 0.0f;
            }

            //enemy rotation in radians          
            float blockroat = _blocklist[0]._floor.Rotation;
            // vector to player - vector to enemy
            _vectToPlayer = playerpos - _blocklist[0].Centre
            angletoplayer = (float)(Math.Atan2(_vectToPlayer.Y, _vectToPlayer.X));
            diff = blockroat - angletoplayer;

            if (diff < -Math.PI)
            {
                diff += (float) Math.PI;
                diff = -diff;
            }
            else if (diff > Math.PI)
            {
                diff -= (float)Math.PI;
                diff = -diff;
            }

            // if enemy angle if off by a certain amount
            if (Math.Abs(diff) >_maxturn)
            {
                if (diff < 0)
                {
                    //turn clockwise
                    _blocklist[0]._floor.Rotation += _maxturn;
                }
                else
                {
                     //turn anti clockwise
                    _blocklist[0]._floor.Rotation -= _maxturn;
                }
            }
Run Code Online (Sandbox Code Playgroud)

UPDATE

我最终使用这样的方法2 ..完美的工作.它也比我以前的代码更整洁

            //enemy rotation in radians from farseer (red line)
            float brot = _blocklist[0]._floor.Rotation + ((float)Math.PI/2);
            //vector from enemy to player (blue line)
            Vector2 _vectToPlayer = playerpos - _blocklist[0].Centre;
            //cross product of 2d vectors
            cross = (_vectToPlayer.X * (float)Math.Sin(brot)) - ((float)Math.Cos(brot) * _vectToPlayer.Y);

            //tolerance for how closely enemy must point towards player
            if (Math.Abs(cross) > 5)
            {
                if (cross > 0)
                {
                    //turn anticlockwise
                    _blocklist[0]._floor.Rotation -= _npcstats.maxturnspeed;
                }
                else
                {
                    //turn clockwise
                    _blocklist[0]._floor.Rotation += _npcstats.maxturnspeed;
                } 
            }
Run Code Online (Sandbox Code Playgroud)

我认为我之前的代码或多或少完全按照建议的方法进行操作1.但是我无法让它工作.我把它归结为farseers坐标系的变幻莫测+它与我自己的交互方式.

Eri*_*ert 10

技术#1:

您使用的是我不熟悉的约定.在你的惯例中,东是0,北是-π/ 2,西是π和-π,南是π/ 2.所有角度都在-π和π之间.

通常,面向东方的角色的角度为零,北方为π/ 2,西方为π,正南方为3π/ 2.所有角度都在0到2π之间.

让我们假设正常的约定而不是你的约定.首先在正常约定中使红色和蓝色矢量角度正确; 你是怎么做到的,取决于你.

从两个角度减去红色矢量的角度.现在我们有一个面向正东方的人.

现在规范化新的蓝色角度; 如果小于0,则加2π.如果它大于2π,则减去2π.这样做直到它在0到2π之间.

现在我们有两个角度; 新红色矢量的角度为零,新蓝色矢量的角度在0到2π之间.

如果新蓝色矢量的角度小于π,则原点处的字符需要向左转.如果它大于π则向右转.

技术#2:

拿你的蓝色和红色矢量非零点,说(bx, by)(rx, ry).现在计算bx * ry - by * rx.如果是正数,则右转,如果是负数,则向左转.如果它为零,那么它们要么直接面向或直接面向; 在这种情况下,你必须通过其他方式找出你所处的情况.(这主要是Jacek的回答更直接.)

  • @GuyeIncognito:所以在你的惯例中,从两者中减去红色角度,将新的蓝色角度归一化到-π和π之间,现在如果新的蓝色角度是负的,则向左转,如果是正的,则向右转. (2认同)

Jac*_*cki 5

如果同时具有蓝色和红色矢量作为Vector3,则可以执行以下操作:

Vector3 crossProduct = Vector3.Cross(red, blue)
if (crossProduct.z > 0)
    // Turn Right
else
    // Turn Left
Run Code Online (Sandbox Code Playgroud)