如何检查一个物体是否几乎停止在libgdx + box2d中移动

时间:2014-02-24 21:59:56

标签: java android libgdx box2d jbox2d

所以,我有一个球员身体+夹具等,它本质上是一个反弹的球。

我想检测它什么时候“完全”移动了。

目前我这样做:

public Boolean isStopped() {
    return body.getLinearVelocity().x <= 0.3f && body.getLinearVelocity().y <= 0.3f;
}

这主要起作用,问题是当玩家遇到某些东西时,它的速度为0时会有一瞬间,所以这会返回true。我真正想要的是在它基本完成时返回true。当我调整游戏世界的物理特性时,最好在我能设定的范围内。

我无法检查它是否正在睡觉,因为它来得太晚,直到它停止有力量作用于它之后才会睡觉,我需要在此之前。

我可以存储停止的时间/已停止的步数,但我希望有一个很好的预先存在的方法,我错过了。

有什么想法吗?

3 个答案:

答案 0 :(得分:4)

您可以跟踪最近的移动并通过每次步骤以当前速度混合来更新它:

float speedNow = body.getLinearVelocity().len();
recentSpeed = 0.1 * speedNow + 0.9 * recentSpeed;
if ( recentSpeed < someThreshold )
    ... do something ...

您需要将recentSpeed设置为适当的高值,否则它可能会在第一个时间步骤中低于阈值。

答案 1 :(得分:1)

看看你是如何确定你的误报是由身体与另一个人接触引起的,为什么不在你的ContactListener的beginContact方法中添加几行,将身体的当前速度存储在其用户数据中?然后你可以在isStopped方法中检查速度。如果存储速度并且当前速度不大,则意味着身体正在反弹它所击中的任何一个:忽略。如果存储速度并且当前速度较大,则球已经反弹并且正在朝着一个新的方向前进:清除存储的速度。如果没有存储的速度并且当前速度低于您的阈值,则您已检测到所寻求的情况。

在您的ContactListener中:

public void beginContact(Contact contact) {
    Body a = contact.getFixtureA().getBody();
    Body b = contact.getFixtureB().getBody();

    if (a == mBall) {
        a.setUserData(a.getLinearVelocity().len());
    } else if (b == mBall) {
        b.setUserData(b.getLinearVelocity().len());
    }
}

在你的isStopped支票中:

public Boolean isStopped() {
    float storedSpd = (Float) body.getUserData();
    float currentSpd = body.getLinearVelocity().len();

    if ((storedSpd > Float.MIN_VALUE) && (currentSpd > storedSpd)) {
        body.setUserData(Float.MIN_VALUE);
        return false;
    } else {
        return (currentSpd < THRESHOLD);
    }
}

这是未经测试的,但你明白了。另外,请记住最初将用户数据设置为Float.MIN_VALUE。

答案 2 :(得分:0)

最后,我只是将每次渲染调用的delta传递给isStopped()方法。

public Boolean isStopped(float delta) {
    boolean isMoving = (
            Math.abs(body.getLinearVelocity().x) >= 0.25f || Math.abs(body.getLinearVelocity().y) >= 0.25f);
    if(isMoving) {
        timeStopped = 0f;
        return false;
    } else {
        timeStopped += delta;
        return timeStopped >= 0.3f;
    }
}

timeStopped只是一个以零开头的类属性。这确实在游戏开始时(在用户移动之前)返回,但在我的应用程序中绝对没问题。除此之外,在这种情况下它已经停止了。

我仍然希望看到一种方法来做到这一点,而不存储额外的废话,因为我猜测box2d必须在某个地方有这个信息,以便弄清楚零速度的身体是否没有作用力或如果它只是在影响后改变方向。