1

オブジェクトがJavaで指定された最大速度でマウスポインタをたどる簡単なアルゴリズムがあります。アルゴリズムの核心はこれです:

// Set up displacement trackers for later.
// (These are used in another part of the algorithm, which rotates
//  the object to face along its path tangent with a moving average.)
double dx = 0, dy = 0;

// ... more code

// Find the angle of travel.
double angle = Math.atan2(m.y - target.getY(), m.x - target.getX());

// Set displacements with polar coordinate transforms.
dx = maxSpeed * Math.cos(angle);
dy = maxSpeed * Math.sin(angle);

// Now go there.
target.setX((int) Math.round(target.getX() + dx));
target.setY((int) Math.round(target.getY() + dy));

これは毎秒30フレームで実行されています。パフォーマンスは問題ではありません。

コードは中規模から大規模の値maxSpeed(5以上で問題ありません)で正常に実行されますが、実際に低い値では、コードによってオブジェクトが特定の角度でのみ移動します。たとえば、maxSpeed = 1では、ターゲットは45°の角度でしか移動できません。


問題を理解する方法は次のとおりです。

maxSpeed等しくしましょう1。したがって、Math.sinMath.cosは常に[-1、1]の範囲の値を返し、また[-1、1]の範囲dydxなります。丸めによって整数に変換する場合(ターゲットのx位置とy位置がint変数として定義されているため)、変位はそれぞれ、、、またはのいずれか-1に丸められ、可能な移動を同じ8つの角度に効果的に制限します。01

したがって、たとえば、オブジェクトが(0、0)で始まり、マウスを(300、100)に置くと、オブジェクトは最初に完全に水平に移動し、次に-45°の角度で移動します。オブジェクトを(ほぼ)一定の角度で、原点から終点まで(ほぼ)直線で移動させたいのですが。

double基になるx座標とy座標を値に変換する以外に、これを行うための最良の方法は何でしょうか。

4

2 に答える 2

1

あなたの最後の文がここでの主要な手がかりのように感じます。ソリューションが「正しく」なるほど、動きの遅いオブジェクトの位置の小数部分を追跡するだけで近似し始めます。なぜ単純にそれをしないのですか?

ただし、それが絶対に不可能な場合は、常にハックがあります。

速度と符号の整数部分を削除して、1次元で一方向に縮小することにより、問題を単純化しましょう。フレームごとにdxピクセルの速度で移動するオブジェクトがあります。dxは0.0から1.0の間です。

フレームの更新を行っています。オブジェクトを何ピクセル移動しますか?ゼロか1つ?

正しい確率で更新するだけでなく、多かれ少なかれスムーズに(等間隔で)更新したいと思います。さらに、私たちの目的は予測可能な視覚的行動であるため、ランダム性を使用したくありません。

それを使用できない場合に必要なのは、フレーム番号を追跡し、等間隔の更新のシーケンスのどこにいるかを知ることです。

かなり簡単な方法で「正しい」結果を得る良い方法は、次のようなものだと思います。

int last_frame = (int) (((double)(current_frame_number-1)) * dx);
int this_frame = (int) (((double)current_frame_number) * dx);
if( this_frame != last_frame ) {
   ++x; // advance one pixel
}

任意の(一定の!)dxに対して、これは正しい結果を与えるはずです。実際には、時々変化するdxでまともな結果が得られると思います。

フレーム番号のオーバーフローの影響は無視しましたが、最小限に抑える必要があります(ただし、1ずつインクリメントする代わりに減算を使用する場合は注意してください)。

不可欠な部分、記号、および2つの次元があるという事実を追加し直す必要があります。フレームごとに速度(2.7、-0.4)で移動する場合は、常にフレームごとに(2,0)移動し、上記の方法をdx = 0.7で使用して、さらに(1,0)移動するかどうかを決定します。 dx = 0.4を使用して、(0、-1)を追加で移動するかどうかを決定します。

ただし、これは理論的には興味深い問題でしたが、実際の実装では、基になる値にdoubleを使用することをお勧めします。上記を理解するのがはるかに難しいという事実に加えて、一定でない速度に直面して正しいことが保証されるわけではありません-したがって、それは明白な解決策よりも複雑で悪いです。

于 2013-03-23T22:33:21.550 に答える
0

私はJavaで少し錆びていますが、三角法ではなくベクトル数学を使用できるかもしれません。

double xPos, yPos; // should be initialized with the starting position and updated with each change in position - rounding on each update will accumulate errors and produce odd behavior as you described
// start of update
Vector2d direction = (new Vector2d(m.x - target.getX(), m.y - target.getY())).normalize(); // create unit vector in the direction of the target
Vector2d velocity = direction.scale(maxSpeed); // set the scalar speed in the direction of the target
xPos += velocity.x;
yPos += velocity.y; 
target.setX((int) xPos); // move (maxSpeed)*cos(angle) units in the x direction
target.setY((int) yPos); // move (maxSpeed)*sin(angle) units in the y direction
// end of update

...動作するはずです-三角法よりも高速です:)。

于 2013-03-23T22:05:49.640 に答える