我正在使用AndEngine / Box2d来开发游戏。我有一个球在屏幕上反弹。我已经成功地通过施加相反的力来忽略重力,但是在初始冲动之后它有一个减速的速度,即使弹性设置为1.基本上我想:
if(speed< a number ) 在运动方向上施加力或冲动(哪个更好?)
我该怎么做?
答案 0 :(得分: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圈就能达到+ - .5的7,这对我来说已经足够了!希望这有助于其他人寻找同样的事情。
答案 1 :(得分: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());
}
这是您必须在管理更新方法或更新处理程序中编写的另一个代码。
答案 2 :(得分:0)
如果球没有与其他任何东西相互作用,那么使用SetLinearVelocity应该没问题,并且它比计算力/脉冲(C ++)更简单:
b2Vec2 currentDirection = body->GetLinearVelocity();
currentDirection.Normalize();
body->SetLinearVelocity( 5 * currentDirection );
需要注意的是,这只能在球自由运动时完成。如果它正在从墙上或世界上的其他东西中弹出,那么这将导致问题。因此,在执行此操作之前,您需要确保它没有触及任何东西。如果GetContactList()返回null,那么正文不会触及任何内容。
这种调整应该足够便宜,以便在每个时间步长,但由于速度不会改变,直到它再次击中,你甚至可以在反弹结束后只做一次。您可以使用联系人监听器并在EndContact回调中检查球是否仍在触摸某些东西,如果没有,则在时间步骤结束后标记正文以进行调整。
答案 3 :(得分: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());
}