2017-12-26 16 views
0

私は受け入れられる解決策に到着せずに何日間も投資してきたので、次の問題を解決する助けが必要です。画面上で指の動きをエミュレートする体を一定の速度で動かす

私は主人公(Heroという名前)を上から見て(トップダウンビューゲーム)、フィールド上を歩くAndroidゲーム(libgdxを使用しています)をやっています。 ユーザは、指をスクリーンに沿って動かすことによってキャラクタを動かす。指はキャラクターにいる必要はありません。

キャラクターは2つのアニメーションを使用します。前方に移動したとき(つまり、ユーザーが「スカイ」からゲームを見てからyが0より大きい場合)、後方に移動するときに別のアニメーションが使用されますつまり、彼の "y"が0より小さい場合、私はトップダウンビューゲームを開発していることを思い出してください)。

最後に、常に一定の速度で移動する必要があります。

要するに、私は指で文字を扱い、指を指す方向に動かしたいと思います。常に一定のスピードです。

私は文字の位置にそれぞれデルタ時間を設定することができれば、これは非常に簡単だろうが、私は唯一の線速度について知っているBOX2D、インパルス、力を使用している、など

私はどこhitbody mouseJointを使用してみました私の主人公(ヒーロー)とグラウンドボディは目に見えない体です。

// Invisible zero size ground body 
// to which we can connect the mouse joint 
Body groundBody; 
BodyDef bodyDef = new BodyDef(); 
groundBody = world.createBody(bodyDef); 

/* player is an instance of my Hero's class, which has a box2d body and 
update, draw methods, etc. 
*/ 
hitBody = player.getB2body(); 
... 

InputProcessor:

@Override 
public boolean touchDown(int i, int i1, int i2, int i3) { 
     gameCam.unproject(testPoint.set(i, i1, 0)); 
     MouseJointDef def = new MouseJointDef(); 
     def.bodyA = groundBody; 
     def.bodyB = hitBody; 
     def.collideConnected = true; 
     def.target.set(testPoint.x, testPoint.y); 
     def.maxForce = 1000.0f * hitBody.getMass(); 
     mouseJoint = (MouseJoint) world.createJoint(def); 
     hitBody.setAwake(true); 
} 

@Override 
public boolean touchUp(int i, int i1, int i2, int i3) { 
    player.getB2body().setLinearVelocity(0,0); 

    // if a mouse joint exists we simply destroy it 
    if (mouseJoint != null) { 
     world.destroyJoint(mouseJoint); 
     mouseJoint = null; 
    } 
    return false; 
} 

@Override 
public boolean touchDragged(int i, int i1, int i2) { 
    // if a mouse joint exists we simply update 
    // the target of the joint based on the new 
    // mouse coordinates 
    if (mouseJoint != null) { 
     gameCam.unproject(testPoint.set(i, i1, 0)); 
     mouseJoint.setTarget(target.set(testPoint.x, testPoint.y)); 
     evaluateMovementDirection(); 
    } 
    return false; 
} 

private void evaluateMovementDirection() { 
    float vy = player.getB2body().getLinearVelocity().y; 
    float vx = player.getB2body().getLinearVelocity().x; 

    // Test to Box2D for velocity on the y-axis. 
    // If Hero is going positive in y-axis he is moving forward. 
    // If Hero is going negative in y-axis he is moving backwards. 
    if (vy > 0.0f) { 
     player.onMovingUp(); // In draw, I'll use a "moving forward" animation 
    } else if (vy < 0.0f) { 
     player.onMovingDown(); // In draw, I'll use a "movieng backwards" animation 
    } else { 
     player.onStanding(); // vy == 0 In draw, I'll use a texture showing my Hero standig. 
    } 
} 

私はこれを取得する問題、私は私の指が非常に速く移動する場合、文字が非常に速く動くことです。キャラクターが常に一定速度で動くようにしたい。

私が試した他のアプローチはパンイベントを使用することです:

GestureListener:

@Override 
public boolean pan(float x, float y, float deltaX, float deltaY) { 
    /* 
    * DeltaX is positive when I move my finger to the left, negative otherwise. 
    * DeltaY is positive when I move my finger down, negative otherwise. 
    */ 

    // In b2body y-axes sign is the opposite. 
    deltaY = -deltaY; 

    // DeltaX and deltaY are in pixels, therefore delta is in metres. 
    Vector2 delta = new Vector2(deltaX/Constants.PPM, deltaY/Constants.PPM); 

    // Deltas too small are discarded 
    if (delta.len() > Constants.HERO_SENSIBILITY_METERS) { 
     /* 
     * origin.x = player.getB2body().getPosition().x 
     * origin.y = player.getB2body().getPosition().y 
     * 
     * destination.x = origin.x + delta.x 
     * destination.y = origin.y + delta.y 
     * 
     * To go from origin to destination we must subtract their position vectors: destination - origin. 
     * Thus destination - origin is (delta.x, delta.y). 
     */ 
     Vector2 newVelocity = new Vector2(delta.x, delta.y); 

     // Get the direction of the previous vector (normalization) 
     newVelocity.nor(); 

     // Apply constant velocity on that direction 
     newVelocity.x = newVelocity.x * Constants.HERO_LINEAR_VELOCITY; 
     newVelocity.y = newVelocity.y * Constants.HERO_LINEAR_VELOCITY; 

     // To avoid shaking, we only consider the newVelocity if its direction is slightly different from the direction of the actual velocity. 
     // In order to determine the difference in both directions (actual and new) we calculate their angle. 
     if (Math.abs(player.getB2body().getLinearVelocity().angle() - newVelocity.angle()) > Constants.HERO_ANGLE_SENSIBILITY_DEGREES) { 
      // Apply the new velocity 
      player.getB2body().setLinearVelocity(newVelocity); 
      evaluateMovementDirection(); 
     } 
    } else { 
     // Stop 
     player.getB2body().setLinearVelocity(0, 0); 
     evaluateMovementDirection(); 
    } 
    return true; 
} 

私はこれを持っている問題は、動きが非常に不安定と「汚い」であるということです。キャラクターが揺れている。

私はこのアプローチを試しました(感謝@六分)。 このコードを使用すると、私のチャレーターは画面に沿ってより多くの流体を移動させます。 これは完璧ではないが、それは私がこれを解決する方法についての提案を必要とする...

@Override 
public boolean pan(float x, float y, float deltaX, float deltaY) { 
    /* 
    * DeltaX is positive when I move my finger to the left, negative otherwise. 
    * DeltaY is positive when I move my finger down, negative otherwise. 
    * Both are in pixels, thus to get meters I must divide by Constants.PPM. 
    */ 

    // In b2body y-axes sign is the opposite. 
    deltaY = -deltaY; 

    /* 
    * origin.x = player.getB2body().getPosition().x 
    * origin.y = player.getB2body().getPosition().y 
    * 
    * destination.x = origin.x + deltaX/Constants.PPM 
    * destination.y = origin.y + deltaY/Constants.PPM 
    * 
    * To go from origin to destination we must subtract their position vectors: destination - origin. 
    * Thus, destination - origin is (deltaX/Constants.PPM, deltaY/Constants.PPM). 
    */ 
    candidateVelocity.x = deltaX/Constants.PPM; 
    candidateVelocity.y = deltaY/Constants.PPM; 

    // Get the direction of the previous vector (normalization) 
    candidateVelocity.nor(); 

    // Apply constant velocity on that direction 
    candidateVelocity.x = candidateVelocity.x * Constants.HERO_LINEAR_VELOCITY; 
    candidateVelocity.y = candidateVelocity.y * Constants.HERO_LINEAR_VELOCITY; 

    // Linear interpolation to avoid character shaking 
    heroVelocity.lerp(candidateVelocity, Constants.HERO_ALPHA_LERP); 

    // Apply the result 
    player.getB2body().setLinearVelocity(heroVelocity); 

    // Depending on the result, we change the animation if needed 
    evaluateMovementDirection(); 
} 
return true; 
} 

何か。つまり、一定速度で画面に沿って指でbox2dキャラクタを移動します。

ありがとうございました。

+0

あなたは生のタッチスクリーン値がために十分に「クリーン」であるかどうかを確認することができます安定した動き?そうでない場合は、ローパスフィルタ処理を実行することを検討してください。 – hexafraction

+0

アドバイスをいただきありがとうございます。私は、libgdxに便利なVector2の関数 "Lerp"があることを知りました。 私が知る限り、Lerp(線形補間)はローパスフィルタと同じではありませんが、(少なくともほとんどの場合は)動作すると思います。 私のキャラクターは、画面の周りを動くと、より安定しているようです。 質問で「私の新しいアプローチ」をチェックしてください。別の提案がありますか?ほんとうにありがとう。 Thks。 – Alvaro

+0

'lerp'は、フィルタリングの代わりに補間するので、あなたがやりたいことを正確に行うことはできません。それはうまくいく可能性がありますが、過去に出会ったことを平滑化する方法ではありません。あなたは、常に動きを(0.7 *入力+ 0.3 * lastFrameMovement)程度にすることで簡単な1次フィルタを作ることができますが、ロールオフ自体に 'deltaTime'を必要としない限り、依然として不正確です。 – hexafraction

答えて

0

は、移動したい方向を計算します。

dragPos.sub(currentPos); 

は、それを正規化し、一定の速度に掛ける:

dragPos.sub(currentPos).nor().scl(CONSTANT_SPEED); 
+0

そうですね、それは私が2番目のアプローチでしたことです: 'Vector2 newVelocity = new Vector2(delta.x、delta.y); newVelocity.nor(); newVelocity.x = newVelocity.x * Constants.HERO_LINEAR_VELOCITY; newVelocity.y = newVelocity.y * Constants.HERO_LINEAR_VELOCITY; ' この問題は、イベントで受け取った値の数が多いことに関連しているようです。私は以前は六分法が述べているように、ある種のローパスフィルタリングが必要です。 – Alvaro

+0

あなたが望むものはあまりにも複雑に見えます。私のアプローチは一定のスピードで動きます。デルタを使用している場合はデルタ時間も考慮してください –

関連する問題