python box2d模拟平抛运动_论述如何基于Box2D模拟星球重力效果
作者:Emanuele Feronato
隨著《Angry Birds Space》的問世,我想你定非常疑惑要如何通過Box2D模擬星球重力。
基本原理非常簡單。
首先,太空沒有重力,所以你將通過如下方式創建沒有重力的b2World世界:
private var world:b2World=new b2World(new b2Vec2(0,0),true);
abspace from emanueleferonato.com
接著就是根據主體和球體位置落實Force。
參考如下腳本:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
public class Main extends Sprite {
private var world:b2World=new b2World(new b2Vec2(0,0),true);
private var worldScale:Number=30;
private var planetVector:Vector.=new Vector.();
private var debrisVector:Vector.=new Vector.();
private var orbitCanvas:Sprite=new Sprite();
public function Main() {
addChild(orbitCanvas);
orbitCanvas.graphics.lineStyle(1,0xff0000);
debugDraw();
addPlanet(180,240,90);
addPlanet(480,120,45);
addEventListener(Event.ENTER_FRAME,update);
stage.addEventListener(MouseEvent.CLICK,createDebris);
}
private function createDebris(e:MouseEvent):void {
addBox(mouseX,mouseY,20,20);
}
private function addPlanet(pX:Number,pY:Number,r:Number):void {
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.restitution=0;
fixtureDef.density=1;
var circleShape:b2CircleShape=new b2CircleShape(r/worldScale);
fixtureDef.shape=circleShape;
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.userData=new Sprite();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var thePlanet:b2Body=world.CreateBody(bodyDef);
planetVector.push(thePlanet);
thePlanet.CreateFixture(fixtureDef);
orbitCanvas.graphics.drawCircle(pX,pY,r*3);
}
private function addBox(pX:Number,pY:Number,w:Number,h:Number):void {
var polygonShape:b2PolygonShape = new b2PolygonShape();
polygonShape.SetAsBox(w/worldScale/2,h/worldScale/2);
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.density=1;
fixtureDef.friction=1;
fixtureDef.restitution=0;
fixtureDef.shape=polygonShape;
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.type=b2Body.b2_dynamicBody;
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var box:b2Body=world.CreateBody(bodyDef);
debrisVector.push(box);
box.CreateFixture(fixtureDef);
}
private function debugDraw():void {
var debugDraw:b2DebugDraw = new b2DebugDraw();
var debugSprite:Sprite = new Sprite();
addChild(debugSprite);
debugDraw.SetSprite(debugSprite);
debugDraw.SetDrawScale(worldScale);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
debugDraw.SetFillAlpha(0.5);
world.SetDebugDraw(debugDraw);
}
private function update(e:Event):void {
world.Step(1/30, 10, 10);
world.ClearForces();
for (var i:int=0; i
var debrisPosition:b2Vec2=debrisVector[i].GetWorldCenter();
for (var j:int=0; j
var planetShape:b2CircleShape=planetVector[j].GetFixtureList().GetShape() as b2CircleShape;
var planetRadius:Number=planetShape.GetRadius();
var planetPosition:b2Vec2=planetVector[j].GetWorldCenter();
var planetDistance:b2Vec2=new b2Vec2(0,0);
planetDistance.Add(debrisPosition);
planetDistance.Subtract(planetPosition);
var finalDistance:Number=planetDistance.Length();
if (finalDistance<=planetRadius*3) {
planetDistance.NegativeSelf();
var vecSum:Number=Math.abs(planetDistance.x)+Math.abs(planetDistance.y);
planetDistance.Multiply((1/vecSum)*planetRadius/finalDistance);
debrisVector[i].ApplyForce(planetDistance,debrisVector[i].GetWorldCenter());
}
}
}
world.DrawDebugData();
}
}
}
整個代碼只創造靜態主體(星球),讓你通過點擊鼠標放置動態主體(碎屑)。
腳本的唯一有趣之處在于更新函數的循環語句,下面我將逐行進行解釋。
for (var i:int=0; i
檢測之前存儲于矢量Vector中的所有碎屑的循環語句在第14行代碼中呈現,在第54行進行更新。
var debrisPosition:b2Vec2=debrisVector[i].GetWorldCenter();
設定碎屑位置。
for (var j:int=0; j
檢測之前存儲于矢量Vector中的所有星球的循環語句將在第13行代碼中呈現,在第38行進行更新。
var planetShape:b2CircleShape=planetVector[j].GetFixtureList().GetShape() as b2CircleShape;
我需要知道星球的質量,因為質量越大,重力吸引力就越強烈。遺憾的是,Box2D靜態主體沒有質量,所以我需要得到星球的圓形模型……
var planetRadius:Number=planetShape.GetRadius();
……設定它的半徑。所以在這種情況下,半徑越大,重力吸引力就越強烈。
var planetPosition:b2Vec2=planetVector[j].GetWorldCenter();
設定星球的位置。
var planetDistance:b2Vec2=new b2Vec2(0,0);
創建新的b2Vec2變量,它將存儲星球和碎屑之間的距離。
planetDistance.Add(debrisPosition);
添加碎屑坐標軸,然后……
planetDistance.Subtract(planetPosition);
……扣除星球坐標軸。
var finalDistance:Number=planetDistance.Length();
計算星球和碎屑之間的距離。
if (finalDistance<=planetRadius*3) {
檢查碎屑是否受到星球重力的影響(游戲邦注:這里碎屑的半徑不能大于星球半徑的3倍)。
planetDistance.NegativeSelf();
插入星球距離,這樣force會按照星球起點的方向移動碎屑。
var vecSum:Number=Math.abs(planetDistance.x)+Math.abs(planetDistance.y);
合計距離矢量分量。因此碎屑遠離星球時,重力吸引力應減弱;碎屑靠近星球時,重力吸引力應增強。
planetDistance.Multiply((1/vecSum)*planetRadius/finalDistance);
這是隨著我們逐步遠離星球,削弱重力的最后公式。
debrisVector[i].ApplyForce(planetDistance,debrisVector[i].GetWorldCenter());
最終force將被運用至碎屑中。
下面是最終結果:
debris from emanueleferonato.com
(本文為游戲邦/gamerboom.com編譯,拒絕任何不保留版權的轉載,如需轉載請聯系:游戲邦)
Simulate radial gravity (also known as “planet gravity”) with Box2D as seen on Angry Birds Space
by Emanuele Feronato
With the launch of Angry Birds Space I am sure you are wondering how to simulate planet gravity with Box2D.
And guess what… the basics are very easy.
First, in space there’s no gravity, so you will create a b2World world without gravity this way:
Then, it’s just a matter of applying Forces according to bodies and planets position.
Look at this script:
The whole code just create static bodies (planets) and let you place dynamic bodies (debris) with the click of the mouse.
The only interesting part of the script is the for loop in the update function, which I’ll explain line by line:
Loop which scans for all debris previously stored in debrisVector Vector declared at line 14 and updated at line 54
Gets debris position
Loop which scans for all planets previously stored in planetVector Vector declared at line 13 and updated at line 38
I need to know the mass of the planet because the bigger the mass, the more intense the gravity attraction. Unfortunately Box2D static bodies do not have mass, so I need to get the circle shape of the planet…
… and get its radius. So in this case the bigger the radius, the more intense the gravity attraction
Gets planet position
Creates a new b2Vec2 variable which will store the distance between the planet and the debris
Adds debris coordinates, then…
… subtracts planet coordinates
Calculates the distance between the planet and the debris
Checks if the debris should be affected by planet gravity (in this case, the debris must be within a radius of three times the planet radius)
Inverts planet distance, so that the force will move the debris in the direction of the planet origin
Gets the sum of distance vector components. I will need this to make gravity attraction weaker when the debris is far from the planet, and stronger when the debris is getting close to the planet
This is the final formula to make the gravity weaker as we move far from the planet
And finally the force can be applied to debris
This is the result:(Source:emanueleferonato)
總結
以上是生活随笔為你收集整理的python box2d模拟平抛运动_论述如何基于Box2D模拟星球重力效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机基础知识与程序设计二,计算机基础与
- 下一篇: 4am永远 鼠标按键设置_4AM碾压性夺