代码之家  ›  专栏  ›  技术社区  ›  Tom Manterfield

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

  •  5
  • Tom Manterfield  · 技术社区  · 11 年前

    所以,我有一个球员的身体+固定装置等,它本质上是一个可以反弹的球。

    我想知道它什么时候“差不多”移动完毕。

    现在我这样做:

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

    这基本上是有效的,问题是当玩家击中某个物体时,在速度为0的瞬间,这是真的。我真正想要的是,当它基本完成时,回归真实。最好是在一个范围内,当我调整游戏世界的物理特性时,我可以将其设置为我喜欢的任何值。

    我不能用检查它是否在睡觉,因为它来的太晚了,直到它停止受力作用后才睡觉,我只需要在之前。

    我只能存储它停止了多长时间/停止的步数,但我希望会有一个我错过的好的预先存在的方法。

    有什么想法吗?

    3 回复  |  直到 11 年前
        1
  •  4
  •   noone    11 年前

    您可以跟踪最近的移动,并通过在每个时间步长中混合一点当前速度来更新它:

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

    你需要设置 recentSpeed 否则它可能在第一时间步骤中低于阈值。

        2
  •  1
  •   Emil Fors    11 年前

    看到您如何确定您的误报是由身体与他人接触造成的,为什么不在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。

        3
  •  0
  •   Tom Manterfield    11 年前

    最后,我简单地将每个渲染调用的增量传递给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必须在某个地方有这些信息,以确定零速度物体是否没有力作用,或者撞击后是否只是改变方向。