3

Java でフロック アルゴリズムをコーディングしていますが、特定の時点で行き詰まっています (2D 平面で Ardor3D ライブラリを使用)。

基本的に、現在の回転に追加する角度の差を見つける必要があります。北が 0 度の極座標で指し示す方法しか得られない場合でも、心配する必要はありません。角度と負の角度のラップアラウンドを考慮して角度差を返すメソッドがあります。

代替テキスト

現時点では、アルゴリズムが最初の回転を参照していないため、明らかに機能しない次のコードがあります。

  long tpf = currUpdateTimeMS - lastUpdateTimeMS;

  Vector2 pos = new Vector2();
  rt.getPosition(pos);

  double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal());
  rt.setRotation(rot);

  pos.addLocal(
   Math.cos((rot - MathUtils.HALF_PI)) * (tpf / 10f),
   Math.sin((rot - MathUtils.HALF_PI)) * (tpf / 10f)
  );
  rt.setPosition(pos);

  super.updateLogic();

更新されたコード(最初の回答から、機能していません):

    long tpf = currUpdateTimeMS - lastUpdateTimeMS;
    //rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));

    Vector2 avgpos = app.getAvgBoidPos(new Vector2());
    Vector2 pos = rt.getPosition(new Vector2());
    avgpos.subtractLocal(pos);

    double angleRads = rt.getRotation() * FastMath.DEG_TO_RAD;
    double rot = MathUtils.acos((
        (avgpos.getX() * MathUtils.sin(angleRads)
    ) +
        (avgpos.getY() * MathUtils.cos(angleRads)
    )) / ((Math.pow(avgpos.getX(), 2) + Math.pow(avgpos.getY(), 2)) * 0.5));

    double adegdiff = rot * FastMath.RAD_TO_DEG;

    rt.setRotation(rt.getRotation() - adegdiff);
    double newrot = rt.getRotation();

    pos.addLocal(
        Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
        Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
    );
    rt.setPosition(pos);

    super.updateLogic();

他の回答に基づく別の変更:

    long tpf = currUpdateTimeMS - lastUpdateTimeMS;
    //rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));

    Vector2 avgpos = app.getAvgBoidPos(new Vector2());
    Vector2 pos = rt.getPosition(new Vector2());
    avgpos.subtractLocal(pos);

    double rot = pos.angleBetween(
        app.getAvgBoidPos(new Vector2()).normalizeLocal()
    ) - (rt.getRotation() * MathUtils.DEG_TO_RAD);

    rt.setRotation(rt.getRotation() - (rot * MathUtils.RAD_TO_DEG));
    double newrot = rt.getRotation();

    pos.addLocal(
        Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
        Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
    );
    rt.setPosition(pos);

    super.updateLogic();

私は数学の問題があまり得意ではないので、数式ではなくコードが役に立ちます:)

入力

  • 事業体の現在の位置
  • エンティティの現在の回転 (極方向) 度

出力

  • 現在の回転に加算または減算する度またはラジアン
  • ... または極指向角度として表される度またはラジアン

あなたが助けることができる場合は、前もって感謝します:)

クリス

4

4 に答える 4

2

内積を使用して、現在の向きと面したい点の間の角度 (ラジアン単位) のコサインを決定できます。ビューイングを行っているエージェントが原点に位置し、Y 軸に対する角度 θ で指定された方向を向いていると仮定します (つまり、0 度は「上」または「北」です)。その方向と点 (x, y) に面している間の角度差 θ' を見つけたいとします。それは次のように与えられます:

θ' = cos -1 [(x*sin(θ) + y*cos(θ)) / sqrt(x 2 + y 2 )]

θ から θ' を差し引くと、エージェントはターゲットに向けられます。

エージェントが原点にない場合は、表示するオブジェクトからエージェントの位置を単純に差し引いて、上記のフォームに表示します。

于 2010-10-29T16:15:23.553 に答える
1

少し話題から外れていますが、エフェクトパッケージ(ardor3d-effects)のパーティクルスウォームとワンダーコードも興味深いと思うかもしれません。

それらはardorsvn、またはここで見つけることができます:

http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/

于 2010-11-27T03:50:27.133 に答える
0

これらの機能を正しく理解していれば、これでうまくいくかもしれません:

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal()) - rt.getRotation();

PS言及するのを忘れました:これrotは角度の違いを意図しています。エンティティをこれだけ回転させると、ターゲットの方を向くはずです。

編集:
ありがとう、コードは役に立ちます(私は誤解していましたangleBetween)。もう一度試してみましょう:

エンティティからポイントまでのベクトルは次のとおりです (構文が間違っている場合はご容赦ください。Java はわかりません)。

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

Vector2 direction = app.getAvgBoidPos(new Vector2());
direction.subtractLocal(pos);

これを正規化して、点を指す単位ベクトルを取得し、角度差を取得します。

double rot = rt.getRotation().angleBetween(direction.normalizeLocal())
于 2010-10-29T18:25:45.373 に答える
0

共通の原点を持つ 2 つのベクトル間の角度を見つける方法の実装です。これは、そこで説明されているアルゴリズムに基づいて一緒にハッキングされています: http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

public class DeltaDoodle {

    private double delta(ColumnVector v1,ColumnVector v2) throws Exception{
        double sp=scalarProduct(v1,v2);
        double magV1=magnitude(v1);
        double magV2=magnitude(v2);
        return Math.acos(sp/(magV1*magV2)) * (180/Math.PI);
    }

    private double scalarProduct(ColumnVector a, ColumnVector b) {
        return (a.x*b.x) + (a.y*b.y);
    }
    private double magnitude(ColumnVector a){
        return Math.sqrt((a.x*a.x) + (a.y*a.y));
    }

    public static void main(String[] args) {
        DeltaDoodle v=new DeltaDoodle();
        try {
            System.out.println("angle: " + v.delta(new ColumnVector(5, 5), new ColumnVector(1,1)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

public class ColumnVector {
    public final double x, y;

    public ColumnVector(double x1, double x2) {
        this.x = x1;
        this.y = x2;
    }
}

それが役立つことを願っています...

于 2010-10-29T16:34:00.773 に答える