パスの最後で移動オブジェクトをスムーズに停止させるにはどうすればよいですか?


8

この質問の言い方は十数通りありますが、私の考えを一致させるために、私は目の前の問題に合わせてそれを表現しています。

そこで、指定されたポイントから別のポイントに移動し、最初のポイントに戻って、2つの間を直線で通過できるようにするフローティングプラットフォームを作成しています。ただし、少し面白くするために、プラットフォームにいくつかのルールを追加したいと思います。

  1. ワールドデータのタイル値全体の複数を移動するようにコーディングしています。したがって、プラットフォームが静止していない場合、少なくとも1つのタイル幅全体またはタイル高さを移動します。
  2. 1つのタイルの長さ内で、停止から指定された最大速度まで加速させたいと思います。
  3. 1つのタイルの長さの距離に達したら、特定のタイル座標で停止するまで減速し、逆のプロセスを繰り返します。

ここに画像の説明を入力してください

最初の2つの部分はそれほど難しくありません。基本的に、3番目の部分では問題があります。プラットフォームがタイル座標で正確に停止するようにしたいのですが、加速度で作業しているので、1つのタイルの長さに達したら、プラットフォームの現在の速度を格納する値に反対方向の加速度を適用し始めるのは簡単に思えます。距離(タイルが複数のタイル長を移動していると仮定しますが、単純にするために、それがそうであると仮定しましょう)-しかし、問題は、この効果を生み出すために増加する加速の正しい値は何でしょうか?どうすればその値を見つけることができますか?


1
現時点で完全な回答をする時間はありませんが、こちらをご覧くださいred3d.com/cwr/steer/gdc99、特に「到着」セクション。その動作を模倣して減速して停止し、逆転して停止から加速します。
MichaelHouse

ブックマークしました。これは、あなたが私に教えてくれた貴重な情報です。
TheBroodian、2012年

この「desired_velocity =(clipped_speed / distance)* target_offset」というのは理にかなっていますが、正確ではありません。desired_velocityを見つけたら、それをオブジェクトの現在の速度から減算しますか?
TheBroodian、2012年

私はそれを使用して加速値を更新します。acceleration = desired_velocity - currentVelocity次に、通常どおりにその加速を適用します。私が何をするかをさらに示す答えを少し作成します。
MichaelHouse

回答:


5

これらのステアリング動作をガイドとして使用します。到着動作を見る:

ここに画像の説明を入力してください

到着動作は、キャラクターがターゲットから遠く離れているときのシークと同じです。ただし、この動作では、ターゲットを全速で移動するのではなく、ターゲットに近づくにつれてキャラクターの速度が低下し、最終的にターゲットと一致する速度まで減速します。

次のような「到着」関数を作成できます。

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

これにより、動いているオブジェクトに適用するために使用する必要がある加速度が更新されます。


そして、明確にするために、linearVelocityは、以前の更新後にオブジェクトが現在移動していた速度です。
TheBroodian、2012年

あなたの言い回しはかなり奇妙です。ただし、linearVelocity == currentVelocityです。
MichaelHouse

3
このアプローチは複雑すぎるため、私はこのアプローチに同意しません。これは、運動方程式(SUVAT公式)を使用して簡単なトゥイーンで行うことができます。小さな代数と、目的のターゲットを正確にヒットするために必要な入力を計算できます。
Andrew Russell

1
あなたが答えでそれを詳しく説明することができればそれは役に立ちますか?
TheBroodian、2012年

@AndrewRussell私もその答えを見たいです。
MichaelHouse

5

このページをご覧ください:http : //sol.gfxile.net/interpolation/index.html

あなたはsmoothstepのような効果が欲しいようです:

smoothstepグラフィック

一番左のポイント、一番右のポイントがプラットフォームで達成する必要がある場合、および完全なシーケンスを作成するために使用する必要がある時間は、次のようなものでかまいません。

foreachフレーム:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

物理エンジンを使用している場合は、インパルスで作成できますが、翻訳するのはそれほど難しくありません。さらにスムーズなプロセスが必要な場合は、smoothstepレベルを上げることができます。 複数のスムーズステップ


3

あるポイントから別のポイントに値を簡単に補間するイージング関数を提供するXnaTweenerを使用できます...

Xna Tweenerプロジェクトに基づいたいくつかのコードとそれがどのように機能するかを示すビデオを含む返信です...

https://gamedev.stackexchange.com/a/26872/8390

[編集]

次のように、プラットフォームの動きを定義する一連のキーが必要です。

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

そして、あなたはこの方法で動きを処理することができます:

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

"DefaultPosition"は開始位置、 "Traslation"は複数のキーの動きを累積し、各キーの移動は前のキーを基準にしています。したがって、比率係数[0..1]を掛けると、補間された相対移動を返します。前のキーからそのキーに到達するには...

ここに、ここで説明するように定義されたプラットフォームの動きを示す別のビデオがあります...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

私はこのコードを理解しやすくするためにやり直しました...多分それはいくつかのバグを持っています...元のコードは同じ動きのいくつかのインスタンスを処理しますが、各インスタンス間でいくつかの遅延があります...このコードは確かにできる簡単に再設計する...


ありがとう、これは役に立ちます。アニメーションのコンテキストのように見えるもので使用されていますが、私は頭の中でそれを私の現在の状況により適したものに翻訳しようとしています。
TheBroodian、2012年

道に迷いました。これを現在の状況に関連付ける方法がまったくわかりません。oo ;;
TheBroodian、2012年

あなたはアニメーションを持っています...位置でアニメーション化しようとしています...
Blau

私を許してください、私が問題を抱えている理由は、このアイデアをブートストラップして、speed = velocity * timeシステムで動作するシステムに変換しようとしているのですが、このシステムは単にオブジェクトの場所を手続き的にナッジ(それに問題はありません、2つを関連付ける適切な方法を見つけるのは難しいだけです)。
TheBroodian、2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.