我需要帮助解决以下问题,因为我已经投入了很多天而没有找到可接受的解决方案。
我正在做一个 Android 游戏(使用 libgdx),从上面可以看到主角(名为 Hero)(自上而下的视图游戏)并在田野上行走。用户通过在屏幕上移动他的手指来移动角色。手指不需要放在角色上。
角色使用两个动画,一个动画在他向前移动时(即当他的“y”大于零时,因为用户从“天空”看游戏),另一个动画在他向后移动时(即当他的“y”小于零,记住我正在开发一个自上而下的视图游戏)。
最后,我需要角色始终以恒定的速度移动。
简而言之,我想用手指处理角色并将其移动到标记我手指的方向,始终保持恒定速度。
如果我可以在每个增量时间设置角色的位置,这将非常容易,但我使用的是 box2d,它只知道线性速度、脉冲、力等。
我尝试使用 mouseJoint,其中 hitbody 是我的主角(英雄),而 groundBody 是一个看不见的身体。
// 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();
...
输入处理器:
@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.
}
}
我遇到的问题是,如果我非常快地移动手指,角色移动得非常快。我希望角色始终以恒定速度移动。
我尝试的另一种方法是使用 pan 事件:
手势监听器:
@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)。使用此代码,我的角色在屏幕上移动得更加流畅。它并不完美,但它是……
@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;
}
我需要一个关于如何解决这个问题的建议。我的意思是,用我的手指在屏幕上以 CONSTANT SPEED 移动一个 box2d 角色。
非常感谢。