0

問題のコードは次のとおりです。

public void calculate() {
        // Center of circle is at (250, 250).
        //THIS ALGORITHM IS NOW PROVEN TO BE WORSE THAN I FEARED...

        /*      What it does:
         *          Moves object around in a circle.
         *          Does not move the object towards the center.
         *          Object always stays on the rim of the circle.
         * 
         *      Algorithm I used. (DOES NOT WORK):
         *          N is normalized vector. 
         *          R = -2*(V dot N)*N + V
         */

        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        double nx = x - 250;
        double ny = y - 250;
        double nd = Math.hypot(nx, ny);
        if (nd == 0)
            nd = 1;
        nx /= nd;
        ny /= nd;
        double dotProduct = vx * nx + vy * ny;
        vx += (float) (-2 * dotProduct * nx);
        vy += (float) (-2 * dotProduct * ny);
        x -= vx * 2;
        y -= vy * 2;
        vx *= 0.99;
        vy *= 0.99;
    }

そして、これが起こることです。

写真。

表示されている黒い線は、紫色のオブジェクト (ボックス) が移動する場所です。たまたま で描いた円の線上にあっただけCanvas.drawCircle()です。

リフレクションが機能しなかった理由がわかりません。オブジェクトが円形の壁に衝突する場合、オブジェクトの速度の方向を反映するべきではありませんか?これは、アルゴリズムが意図したものです? または、間違ったアルゴリズムを使用しましたか?

どんな助けでも大歓迎です。前もって感謝します。

4

3 に答える 3

2

任意の角度のまっすぐな壁で跳ね返ることはできますか? それが最初のステップです。(速度ベクトルの極座標表現の方が操作しやすい場合があります。)

それが機能するようになると、それはかなり簡単なはずです。円から跳ね返ることは、接触点で接しているその円の接線から跳ね返るようなものです。

この接線は、接触点の半径ベクトル (つまり、オブジェクトの位置から円の中心を指すベクトル) に垂直であることを観察することで計算できます。

于 2012-08-20T15:38:13.153 に答える
1

これは私が得たものであり、私の調査結果を皆さんと共有します。

public void calculate() {
    // Center of circle is at (250, 250). Radius is 40.
    //THIS ALGORITHM IS PROVEN TO BE BETTER THAN I FEARED...

    /*      What it does:
     *          Moves object around in a circle, if object is 
     *              inside of circle.
     *          Does not move the object towards the center, 
     *              nor outwards. This is crucial.
     *          Object always stays on the rim of the circle, 
     *              if the collision detection allows it to.
     * 
     *      Algorithm I used. (DOES WORK, NOT EXPECTING THIS THOUGH.):
     *          N is normalized vector. 
     *          R = -2*(V dot N)*N + V
     */



    double nx = x - 250;
    double ny = y - 250;
    double nd = Math.hypot(nx, ny);
    if (nd < 40){
        vx += Accelero.X * 0.1;
        vy += Accelero.Y * 0.1;
        x -= vx;
        y -= vy;
        vx *= 0.9;
        vy *= 0.9;
        return;
    }

    vx += Accelero.X * 0.1;
    vy += Accelero.Y * 0.1;


    if (nd == 0)
        nd = 1;
    nx /= nd;
    ny /= nd;
    double dotProduct = vx * nx + vy * ny;
    vx += (float) (-2 * dotProduct * nx);
    vy += (float) (-2 * dotProduct * ny);
    x -= vx * 2;
    y -= vy * 2;
    vx *= 0.99;
    vy *= 0.99;
}

関数内に衝突検出を埋め込んだため、基本的にこの関数は可能な限り効率的ではなくなりました。それは主な焦点ではないので無視してください。

円の半径は 40、(x,y) の位置は (250,250) です。

オブジェクトが円上にあるか、円の中心から離れている場合にのみ、アルゴリズム R = -2*(V dot N)*N + V で与えられる衝突応答を計算する必要があります。ここで、法線ベクトルは次のとおりです。 N はすでに正規化されています。

アルゴリズムは確かに正しいです。衝突検出のブール条件は、オブジェクトが円の縁にとどまり、その上を一周する原因です。

@trashgod が提供した他のアルゴリズムが間違っているとは言いませんでした。これは、オブジェクトが異常に動く原因となる奇妙な問題が原因です。私が使用している API のせいだと思いますが、これは double を許可していませんでしたが、間違っている可能性があります。問題の原因を見つけることができませんでした。また、これ以上詳しく調べないことも嬉しく思います。

衝突検出ブール条件自体は、わずかに変更された場合、すべてを変更する可能性があります。どういうわけかマイナス記号 (この場合は NOT 記号) を忘れたように見えることを @nm が指摘していなければ、それがどれほど些細なことであるかにおそらく気づかなかったでしょう。

于 2012-08-21T10:58:11.863 に答える