c# - 从两个角度算出顺时针转还是逆时针转

标签 c# .net math xna angle

我正在用 XNA 制作游戏。 我有敌人和玩家。 敌人应该逐渐转向玩家。他们应该弄清楚是否需要顺时针或逆时针旋转,以较短的为准。

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

虽然我有一些奇怪的行为。让我们在下面的场景中说。敌人可能会一路转向错误的方向。

enter image description here

我的代码(如下)越来越长,但我仍然遇到问题。这段代码是敌人类 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;
                }
            }

更新

我最终使用了这样的方法 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;
                } 
            }

我认为我以前的代码或多或少完全符合建议的方法 1。 但我无法让它工作。我把这归结为远见者坐标系的变幻莫测 + 它如何与我自己的坐标系相互作用。

最佳答案

技巧#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 更直接地回答。)

关于c# - 从两个角度算出顺时针转还是逆时针转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16613616/

相关文章:

c# - 大型列表上的 plinq 需要花费大量时间

c# - 新线程和新任务之间的区别?

.net - 查看 .NET 应用程序中所有调用的最简单方法(分析/检测)

.net - FileSystemWatcher保留父目录

java - 非常不寻常的舍入

c# - Lazy<T> ExecutionAndPublication - 可能导致死锁的示例

c# - C# 中的 Java 方法 'MessageDigest.getInstance()' 相当于什么?

.net - 监控任何应用程序中的选择

实现模 2 算术的 Python 模块矩阵类?

从世界空间骨骼矩阵计算绑定(bind)姿势/蒙皮矩阵