1

状況

私はしばらくの間、この問題に頭を悩ませてきました。基本的に、シミュレーションの各ステップで、設定された速度dr (ラジアン/秒)で目的の角度wr (ラジアン)に変更したい角度r (ラジアン)があります。したがって、ステップごとに新しい角度nrが必要です。ここで、nr = r + dr * dtであり、dtは最後のステップからのデルタ時間です。

角度はスペース[-pi、pi]にあり、デルタ角度は最短の回転方法によって決定されます。ステップごとに、デルタ角度が現在の回転に追加され、[-pi、pi]にラップされ、新しい角度として保存されます。

私は自分のステップで無限の精度を持っていないので、明らかに-事実上-目的の角度にまっすぐに当たることはありません。したがって、目的の回転に達したとき-そして交差したとき-を見つけて、回転を停止して角度を設定する必要があります希望の角度に。擬似コードの場合:

if rotationSpeed!= 0
     angle = WrapRotation(angle + rotationSpeed * deltaTime)
     if desiredAngle has been reached or crossed
       angle = desiredAngle
       rotationSpeed = 0

問題

ほとんどすべての状況で、これは簡単に実行できますが、角度が十分に高いまたは低い(-piまたはpiに近い)場合、新しい角度で「境界」を越えて、いわば複雑になります。私のすべての試みは、現在、以前、および望ましいローテーションで起こりうるすべての状況をカバーすることができませんでした。だから私はあなたがこれの解決策を知っているかどうかあなたに尋ねていますか?

必要に応じて、以下にコード(C#)を添付しました。

// Sets the desired rotation and rotation speed in radians/second:
public void SetRotation(float rotation, float speed)
{
        desiredRotation = MathHelper.WrapAngle(rotation);
        if (desiredRotation != this.rotation)
        {
            // Determine the shortest way to turn (indicated by the sign of speed)
            float a = desiredRotation - this.rotation;
            if (a > Math.PI) a -= 2 * (float)Math.PI;
            if (a < -Math.PI) a += 2 * (float)Math.PI;

            desiredRotationSpeed = a < 0 ? -speed : speed;
        }
 }

 // Update is called per each step. Takes in the amount of seconds since the last call.
 public void Update(float seconds)
 {
        /* Other stuff */
        if (desiredRotationSpeed != 0)
        {
            float delta = desiredRotationSpeed * seconds;
            rotation = MathHelper.WrapAngle(rotation + delta);
            if( /* This is the part I'm struggling with. */ )
            {
                desiredRotationSpeed = 0f;
                rotation = desiredRotation;
            }
        }
        /* Other stuff */
 }

通常の状況(非サイクリック動作)では、次のように機能します。

if (Math.Abs(value - desiredValue) < Math.Abs(deltaValue))
    /* Desired has been reached. Do stuff! */

明確にするために。現在の角度を希望の角度に設定して回転を停止できるように、希望の角度がいつヒットしたか(そして精度のために超えたか)を見つけたいと思います。

あなたの助けをどうもありがとう!これは本当に簡単な解決策だと思います!:3

4

2 に答える 2

2

目的のローテーションを超えるのなぜですか? 現在の角度と目的の角度の間の角度の最小値としてデルタを計算し、移動したいデルタを計算してみませんか? そうすれば、最後のステップで正確に目的の角度に移動できます。

また、コードを変更して、2つの値をSetRotation保存するだけで、計算で目的の角度を現在の角度と比較し、差を計算し、速度値 x 秒数に制限してから移動できるようにします。その量 (方向 +ve または -ve の適切な if ステートメントを使用)。desiredRotationspeedUpdate

于 2012-05-30T17:01:51.307 に答える
0

Ian Mercer のおかげで、何をすべきかがわかりました。

通常の番号の場合と同様に:

if (Math.Abs(value - desiredValue) < Math.Abs(deltaValue)) 
    /* Desired has been reached. Do stuff! */ 

私が必要としたのは、角度間の最小角度を見つけるための三角法だけでした。2 つの角度を、origo からのベクトル (または、2 つのベクトルと x 軸の間の角度を持つ 2 つのベクトル) として見ると、最小の角度を簡単に見つけることができます。次の点を考慮してください。

Math.Atan2(Math.Sin(toAngle - fromAngle), Math.Cos(toAngle - fromAngle))

それは私に最小の角度を与えるでしょう。回転を停止するタイミングを見つけるには、回転した距離が 2 つの角度の間の最小の距離/角度よりも大きいかどうかを確認するだけです。

上記のコードを次のように変更すると、問題が解決します。

  double distance = Math.Atan2(Math.Sin(desiredRotation - rotation),
       Math.Cos(desiredRotation - rotation));
  if(Math.Abs(distance) < Math.Abs(delta))
  {
       desiredRotationSpeed = 0f;
       rotation = desiredRotation;
  }

親愛なるジョージ・ポーリャに相談しておけばよかったのに。助けてくれてありがとう、私は正しい方向へのプッシュが必要でした!

于 2012-05-30T17:24:28.617 に答える