5

我正在使用 AndEngine/Box2d 开发游戏。我有一个在屏幕上弹跳的球。我已经通过施加相反的力成功地使它忽略了重力,但是即使弹性设置为1,它也会在初始冲动后减速。基本上我想:

if(speed < a number ) 在运动方向上施加力或冲量(哪个更好?)

我该怎么做?

4

4 回答 4

6

不幸的是,球正在与其他物体相互作用,因此设置速度不起作用,但我找到了解决方案!

使用力量和相当广泛的三角,我终于想出了:

private static class Ball extends Sprite  {
    Body body;

    public Ball(final float pX, final float pY, final ITextureRegion pTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
        super(pX, pY, pTextureRegion, pVertexBufferObjectManager);
        body = PhysicsFactory.createCircleBody(mPhysicsWorld, this, BodyType.DynamicBody, PhysicsFactory.createFixtureDef(0, 1, 0));
        body.applyLinearImpulse(((float)5),(float) 5, body.getWorldCenter().x,  body.getWorldCenter().y);
        mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(this, body, true, true));
        scene.attachChild(this);
    }

    @Override
    protected void onManagedUpdate(final float pSecondsElapsed) {       
        body.applyForce(new Vector2(0,-SensorManager.GRAVITY_EARTH), new Vector2(body.getWorldCenter()));

        float vx = body.getLinearVelocity().x, vy = body.getLinearVelocity().y, vr=(float) Math.sqrt(vx*vx+vy*vy);
        float t= (float) Math.atan(Math.abs(vy/vx));
        if(vr<destroyerVelocity){
            if(vx>0&&vy<0)
                body.applyForce((float) ((destroyerVelocity-vr)*Math.cos(t)*body.getMass()), (float) (-(destroyerVelocity-vr)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx>0&&vy>0)
                body.applyForce((float) ((destroyerVelocity-vr)*Math.cos(t)*body.getMass()), (float) ((destroyerVelocity-vr)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx<0&&vy>0)
                body.applyForce((float) (-(destroyerVelocity-vr)*Math.cos(t)*body.getMass()), (float) ((destroyerVelocity-vr)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx<0&&vy<0)
                body.applyForce((float) (-(destroyerVelocity-vr)*Math.cos(t)*body.getMass()), (float) (-(destroyerVelocity-vr)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
        }
        if(vr>destroyerVelocity){
            if(vx>0&&vy<0)
                body.applyForce((float) (-(vr-destroyerVelocity)*Math.cos(t)*body.getMass()), (float) ((vr-destroyerVelocity)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx>0&&vy>0)
                body.applyForce((float) (-(vr-destroyerVelocity)*Math.cos(t)*body.getMass()), (float) (-(vr-destroyerVelocity)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx<0&&vy>0)
                body.applyForce((float) ((vr-destroyerVelocity)*Math.cos(t)*body.getMass()), (float) (-(vr-destroyerVelocity)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
            else if(vx<0&&vy<0)
                body.applyForce((float) ((vr-destroyerVelocity)*Math.cos(t)*body.getMass()), (float) ((vr-destroyerVelocity)*Math.sin(t)*body.getMass()), body.getWorldCenter().x,  body.getWorldCenter().y);
        }
        super.onManagedUpdate(pSecondsElapsed);
    }
}

本质上,它的作用是创建一个身体并对其施加冲动以使其移动(由于某种原因比力好得多)。每次更新时,都会施加与重力相反的力,以使球保持在空中(基本上是浮动的)。弹性设置为 1,因此碰撞几乎是完全弹性的。现在是棘手的部分:我计算了 x 和 y 速度(分别为 vx 和 vy)并使用它们来计算合成速度(vr)和它们行进的角度(t)。

如果 vr 小于我想要的速度(destroyerVelocity),则施加一个力将其撞回驱逐舰速度。由于 F=mv/t 并且我只使用 t=1,所以在一个方向上施加的力等于所需速度 - 实际速度 * x/y(即 cos/sin)* 物体的质量。如果物体沿 x 正方向和 y 负方向行进,则施加 (x,-y) 的力,依此类推。

为了使速度尽可能接近驱逐舰的速度,如果恰好大于驱逐舰的速度,我必须向相反方向施加一个力。这是以相同的方式完成的,只是使用了相反的力量。

运行结果速度的日志语句(destroyerVelocity 为 7),它的内容如下:6.900001、6.9995001、7.00028、7.13005、...

虽然球有时会飙升到 15 或 20,但通常只需要 2 或 3 圈就可以在 7 的 +- .5 范围内,这对我来说已经足够了!希望这可以帮助其他寻找相同事物的人。

于 2012-06-29T20:02:12.070 回答
3

要在移动方向上施加连续的力,您可以使用以下代码。

Vector2 velocity = this.getBody().getLinearVelocity();
        preX = velocity.x / (Math.abs(velocity.x));
        preY = velocity.y / (Math.abs(velocity.y));

        if (Math.abs(velocity.x) < 5) {
            this.body.setLinearVelocity(preX * 5, velocity.y);
        }
        if (Math.abs(velocity.y) < 5) {
            this.body.setLinearVelocity(velocity.x, preY * 5);
        }

编辑 :

currentVelocity = bulletBody.getLinearVelocity();

                    if (currentVelocity.len() < speed
                            || currentVelocity.len() > speed + 0.25f) {

                        velocityChange = Math.abs(speed
                                - currentVelocity.len());
                        currentVelocity.set(currentVelocity.x
                                * velocityChange, currentVelocity.y
                                * velocityChange);

                        bulletBody.applyForce(currentVelocity,
                                bulletBody.getWorldCenter());
                    }

这是您必须在管理更新方法或更新处理程序中编写的另一个代码。

于 2012-06-29T07:27:16.747 回答
0

如果球没有与其他任何东西相互作用,那么使用 SetLinearVelocity 应该没问题,它比计算力/脉冲 (C++) 更简单:

b2Vec2 currentDirection = body->GetLinearVelocity();
currentDirection.Normalize();
body->SetLinearVelocity( 5 * currentDirection );

需要注意的是,这只能在球自由运动时进行。如果它正好在从墙壁或世界上其他东西反弹的中间,这将导致问题。因此,在执行此操作之前,您需要确保它没有触及任何东西。如果 GetContactList() 返回 null 则主体没有接触任何东西。

这种调整应该足够便宜,可以在每个时间步中进行,但由于速度在再次击中某物之前不会改变,你甚至可以在反弹结束后只做一次。您可以使用接触侦听器并在 EndContact 回调中检查球是否仍在接触某物,如果没有,则在时间步结束后标记身体以进行调整。

于 2012-06-29T16:10:32.557 回答
0

我在我的更新功能中使用它来保持球的速度。

    speed = ball.getLinearVelocity().length()
    maxSpeed = 10;

        if (speed > maxSpeed ){
            ball.setLinearDamping(0.5);
        }
        else if (speed < maxSpeed) {
            ball.setLinearDamping(0.0);
        }
        if (speed < maxSpeed ){

            var currentVelocity = ball.getLinearVelocity();

            currentVelocity.set(currentVelocity.x * 1.1, currentVelocity.y * 1.1);

            ball.applyForce(currentVelocity,ball.getWorldCenter());         
}
于 2013-04-05T10:52:04.793 回答