2012-06-29 13 views
4

我使用AndEngine/Box2d開發遊戲。我有一個彈跳在屏幕周圍的球。我已經成功地做它通過使用相反的力無視重力,但它有一個租賃的初始衝動後慢,甚至設置爲1的彈性基本上我想:我如何在身體的行走方向上施加力量(Box2D)?

如果(速度< 一編號) 在運動方向上施加力或衝動(哪個更好?)

我該怎麼做?

回答

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,這對我來說已經足夠了!希望這可以幫助其他人尋找相同的東西。

+0

使CPU佔用更少的一種方法是將第一個if語句更改爲:if((destroyerVelocity-vr)> acceptedVelocityError),並將第二個if語句更改爲:if((vr-destroyerVelocity)> acceptedVelocityError)。然後,您將acceptedVelocityError設置爲.5。這樣,如果速度與期望速度相差小於0.5,則不會施加力。它加快了fps很多。 – rphello101

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()); 
        } 

這是你必須寫在管理更新方法或更新處理器的另一個代碼。

+1

設置速度與施加力不一樣 – Andrew

+0

您可以按照上述相同的方式更改將力施加到身體中心的功能。 – Siddharth

+0

我想知道這是否會在發生碰撞時導致一些奇怪的行爲 - 對象可能會在一秒鐘內放慢速度,例如隧道穿過牆壁。 – JohnEye

0

如果球不與任何其他交互然後使用SetLinearVelocity應該罰款,這將是比計算力/衝量(C++)簡單:

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

需要注意的是,這隻能是球在自由運動時完成。如果它正處於從牆上或其他地方反彈的中間,這會造成問題。所以在做這件事之前你需要確保它沒有碰到任何東西。如果GetContactList()返回null,那麼主體沒有觸及任何東西。

這種調整應該是足夠便宜,在每個時間步長進行,但由於速度不會改變,直到它再次擊中的東西,你甚至可以用它做的只是一次反彈結束後離開。您可以使用聯繫人偵聽器並在EndContact回調中檢查球是否仍然觸及某些事物,如果沒有,請在時間步驟結束後標記主體以進行調整。

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());   
}