2017-12-26 4 views
0

허용되는 솔루션에 도달하지 않고 며칠을 투자 했으므로 다음 문제에 대한 도움이 필요합니다.화면에서 일정한 속도로 손가락 움직임을 에뮬레이션하는 몸체 이동

저는 주인공 (Hero)이 위에서 (위에서 아래로보기 게임) 보이고 경기장을 걷는 Android 게임 (libgdx 사용)을하고 있습니다. 사용자는 손가락을 화면을 따라 움직여 문자를 움직입니다. 손가락이 캐릭터에 있어야 할 필요는 없습니다.

캐릭터는 앞으로 움직일 때 (즉, 사용자가 "하늘"에서 게임을 본 후 "y"가 0보다 큰 경우) 한 애니메이션과 그가 뒤로 이동하면 다른 애니메이션을 사용합니다 즉, "y"가 0보다 작 으면, 나는 하향식 뷰 게임을 개발 중이다.)

마지막으로 항상 일정한 속도로 움직이는 캐릭터가 필요합니다.

간단히 말해서, 나는 손가락으로 캐릭터를 처리하고 손가락으로 지시하는 방향으로 항상 움직이고 싶습니다. 항상 일정한 속도입니다. 내가 어디 hitbody mouseJoint를 사용하여 시도

나는 캐릭터 각각의 델타 시간의 위치를 ​​설정할 수 있다면

매우 쉬운 것입니다,하지만 난 등 만 linearVelocity, 충동, 힘에 대해 알고 Box2D의를 사용하고 있습니다 내 주인공 (영웅)이며 땅바닥은 보이지 않는 몸입니다.

// 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; 
} 

나는이 함께이 문제는 움직임이 매우 불안정하고 "더러운"는 것이다. 캐릭터가 흔들리고있다.

나는이 접근법을 시도했다. (감사합니다 @ hexafraction). 이 코드를 사용하면 내 charecter가 화면을 따라 더 많은 유체를 이동시킵니다.

@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

당신이 원시 터치 스크린 가치가 충분히 "깨끗한"여부를 확인할 수 있습니다

dragPos.sub(currentPos); 

을 정상화하고, 일정한 속도로 번식을 꾸준한 운동? 그렇지 않은 경우 로우 패스 필터링 작업을 수행하는 것을 고려하십시오. – hexafraction

+0

조언을 주셔서 감사합니다.나는 libgdx가 Vector2에서 "Lerp"라는 함수를 가지고 있다는 것을 알게되었다. 필자가 아는 한 Lerp (선형 보간법)는 저역 통과 필터와 같지 않지만 작동하는 (적어도 대부분의 경우) 것으로 생각됩니다. 화면에서 움직일 때 내 캐릭터가 더 안정적으로 보입니다. 질문에서 "내 새로운 접근법"을 확인해 주시겠습니까? 또 다른 제안이 있니? 정말 감사. Thks. – Alvaro

+0

나는'lerp'가 당신이 원하는 것을 정확하게 수행하는지 모르겠다. 왜냐하면 필터링보다는 보간법이기 때문이다. 그것은 그럴듯 해 보일 수도 있지만, 과거에 내가 만난 것을 부드럽게하는 방법이 아닙니다. 당신은 항상 (0.7 * input + 0.3 * lastFrameMovement) 정도의 움직임을 취함으로써 간단한 first-order-ish 필터를 만들 수 있지만 롤오프 자체에'deltaTime'을 포함시키지 않으면 여전히 부정확 할 수 있습니다. – hexafraction

답변

0

이동하려는 방향 계산 :

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

예, 정확히 두 번째 접근법에서 그랬습니다 : '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; ' 이 문제는 이벤트에서받는 값의 수가 많다는 것과 관련이 있습니다. 나는 hexafraction이 이전에 말했듯이 일종의 로우 패스 필터링이 필요하다. – Alvaro

+0

당신이 원하는 것이 지나치게 복잡해 보입니다. 내 접근 방식은 일정한 속도로 움직일 것입니다. 델타를 사용하는 경우 델타 시간도 고려해야합니다. 왜 그런지 알 수 있습니다. –

관련 문제