2

時間「t」で評価され、パスの種類に基づいて方向と位置を返すパスがあります。

時間の値は、パスの種類によって影響を受けます。

switch (type)
{
    case PathType.Closed:
        time = ToolBox.Wrap(time, StartTime, EndTime);
        break; // Wrap time around the path time to loop

    case PathType.Open:
        time = ToolBox.Min(time, EndTime);
        break; // Clamp the time value to the max path time range

    case PathType.Oscillating:
        break;
}

ミッシングリンクは振動しています。

私の質問は、2 つの値の間で振動するための効果的で効率的な方法は何ですか?

たとえば (2, 7)。時間が 7 に達すると反転して 2 に向かって減少し、2 に達すると反転して 7 に向かって増加します。

アルゴリズムは、元の値に基づいて値を増減するかどうかを知る必要があるため、値が 9 の場合、答えは 7 - (Abs(7 - 9) であることがわかります。値が 14 の場合、値は折り返されているため、 1の増加をもたらします。

値を大きくすると、元の範囲をラップする回数に応じて値が増減します。

説明するのが難しいと思うので、それが理にかなっていることを願っています。

編集:

浮動小数点値では振動しません:

        for (float i = 0; i < 100; i += 0.1f)
        {
            Console.WriteLine("{0} {1}", i, Oscillate(2.5f, 7.5f, i));
        }

    private float Oscillate(float min, float max, float value)
    {
        float range = max - min;

        float multiple = value / range;

        bool ascending = multiple % 2 == 0;
        float modulus = value % range;

        return ascending ? modulus + min : max - modulus;
    }
4

5 に答える 5

9

これが私が思いついたものです:

public static int Oscillate(int input, int min, int max)
{
    int range = max - min ;
    return min + Math.Abs(((input + range) % (range * 2)) - range);
}

input0から始まるカウンターになると思います。

于 2012-07-18T15:11:17.097 に答える
4

理想的には、この機能をある種のクラスに抽象化する必要があり、使用時に実装が実際にどのように機能するかを気にする必要はありません。これが C++ でどのように見えるかについての最初の見解です (私の C# は少し錆びています)。C# に簡単に組み込むことができると思います。

class oscillator
{
  private:
    float min;
    float max;

    static float mod(float num, float div)
    {
        float ratio = num / div;
        return div * (ratio - std::floor(ratio));
    }

  public:
    oscillator(float a, float b)
      : min(a < b ? a : b), max(a > b ? a : b) {}

    float range() ( return max-min; }

    float cycle_length() { return 2*range(); } 

    float normalize(float val)
    {
        float state = mod(val-min, cycle_length());

        if (state > range())
            state = cycle_length()-state;

        return state + min;
    }
};
于 2012-07-18T17:35:04.903 に答える
3

これにより、数値が2から7の間で振動します。この例では、時間は整数です。

bool isIncreasing = time <= 7;
for (int i = 0; i < 20; i++) //some random loop
{
    time = time + (isIncreasing ? 1 : -1);
    if (time >= 7 || time <= 2) isIncreasing = !isIncreasing;
}
于 2012-07-18T14:39:37.360 に答える
1

フロート値を説明するための新しい答え:

    // Note: Increase FACTOR depending on how many decimal places of accuracy you need.
    private const float FACTOR = 10;

    public void Test()
    {
        for (float i = 0; i < 1000; i += 0.1F)
        {
            Console.WriteLine("{0} {1}", i, Oscillate(2.5F, 7.5F, i));
        }
    }

    private float Oscillate(float min, float max, float time)
    {
        return (float)(Oscillate_Aux(Upscale(min), Upscale(max), Upscale(time))) / FACTOR;
    }

    private int Upscale(float value)
    {
        return (int)(value * FACTOR);
    }

    private int Oscillate_Aux(int min, int max, int time)
    {
        int range = max - min;

        int multiple = time / range;

        bool ascending = multiple % 2 == 0;
        int modulus = time % range;

        return ascending ? modulus + min : max - modulus;
    }
于 2012-07-18T14:55:26.367 に答える
0

あなたが説明していることは、2 つの値の間の周期的な線形補間によく似ています。XNA のMathHelper.Lerp関数を振動の基礎として使用することを検討してください。

パーセンテージを使用して、3 番目のパラメーターとして振動を制御することに注意してください。時間 t 値をパーセンタイルに変換する方法を理解する必要がありますが、ex から始めることができます。sin(t) を実行して、物事がどのように機能するかを確認します。

XNA をプロジェクトにインポートすることに気が進まない場合、核となる方程式は非常に単純です。

value1 + (value2 - value1) * amount

編集: あなたの質問が本当に「2 つの値の間で振動するための効率的で効果的な方法は何ですか?」である場合、Math.Sin(t) (または Cos) は 0 と 1 の間の定期的な振動を提供できます。


于 2012-07-18T15:03:19.113 に答える