Box2D - první kroky - 2. díl

27.4.2009· Autor: Ivan Kuckir· Počet komentářů: 11

V předchozím článku jsme si řekli trochu teorie, dnes se podíváme na praktické využití a způsob práce s engine. Vytvoříme si svět, vložíme do něj několik těles a necháme je spadnout dolů.

Příprava nové třídy

V prvním článku jsme si nainstalovali knihovny Box2D, nyní si připravíme prostředí.

Vytvořili jsme si ve flashi nový FLA soubor a jako jeho hlavní třídu jsme nastavili "Main" (nebo jsme vložili UIComponent ve flexu). Teď si vytvoříme soubor "Main.as", který umístíme vedle FLA (nebo ve flexu do složky vedle MXML). FPS jsem nastavil na 60. Obsah Main.as bude následující:

package{
 
 import flash.display.Sprite;
 import flash.events.Event;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
  
 public class Main extends Sprite{
  
  public var world:b2World;
 
  public function Main(){ 

   addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
   /////////////////

  }  

  public function Update(e:Event):void{

  }  
 
 }   

}   

Naimportovali jsme potřebné knihovny, nadefinovali svět (world), který je typu b2World, a přidali jsme eventLisnener na událost enterFrame. Následující kódy budeme psát do funkce Main, tedy tam, kde jsou lomítka.

Základem je svět

O teoretickém světě můžeme říci, že je definován od mínus nekonečna do plus nekonečna. V počítačích však žádná hodnota nemůže růst do nekonečna, proto musíme určit Axis-Aligned Bounding Box (zkráceně AABB, třída b2AABB). Jedná se o prostor, uvnitř kterého se budou počítat souřadnice objektů. Pokud se objekt dostane mimo něj, zůstane uložený v paměti, ale už není aktivní součástí daného světa.

Další potřebnou věcí je gravitace. Ta je udávaná vektorem o dvou proměnných - třída b2Vec2.  První je X-ová souřadnice, druhá Y. Můžete si ji představit jako šipku, vedoucí z [0; 0] do daných souřadnic. Směrem šipky se budou pohybovat padající tělesa, délka šipky určuje velikost síly.

Obsahu našeho světa můžeme povolit stav spánku. Stav spánku u tělesa znamená, že pokud se těleso nepohybuje (nebo rozmezí, ve kterém se pohybuje, je velmi malé), potom u něj přestaneme počítat jeho vlastnosti. To jednoduše proto, abychom ulehčili práci CPU a zbytečně nezpomalovali běh aplikace. Těleso se zase probudí, když do něj narazí jiné těleso, nebo když na něj aplikujeme sílu nebo impuls.

Rozhodl jsem se, že počátek fyzikálního světa bude levý horní roh okna aplikace (tedy X roste doprava, Y dolů) a že 1 metr bude roven 100 pixelům. To však není nutné a vy si to můžete navolit, jak jen budete chtít. Jak jsem již řekl v předchozím díle, hodnoty jsou v metrech, kilogramech a sekundách.

 var worldAABB:b2AABB = new b2AABB();         //  AABB prostor, jedná se o jakýsi obdélník

 worldAABB.lowerBound.Set(-100.0, -100.0);    //  dolní mez (levý horní roh obdélniku)
 worldAABB.upperBound.Set(100.0, 100.0);      //  horní mez (pravý dolní roh obdélníku)
 
 var gravity:b2Vec2 = new b2Vec2 (0.0, 10.0); //  vektor gravitace
//  vede kolmo dolů, můžete ho udělat i nahoru nebo do strany pod různými úhly

 var doSleep:Boolean = true;                  //  dovolíme objektům spánek
 
 world = new b2World(worldAABB, gravity, doSleep);  // z proměnných vytvoříme svět

První tělesa

Samotná tělesa - b2Body -  jsou určena definicí tělesa - b2BodyDef a definicí tavaru - b2ShapeDef

  • Definice tělesa (b2BodyDef) - zde je uložena především pozice tělesa ve světě. Je zvykem do ní ukládat název herce (jako userData), aby těleso a jeho herec byly mezi sebou aspoň trochu propojeni.
  • Definice tvaru (b2ShapeDef) určuje především tvar tělesa. Vychází z ní třídy b2PolygonDef a b2CircleDef. Dále je zde uvedena hustota (density), tření (friction) a "elastičnost" (restitution).
    V Box2D se nerozlišují tělesa statická a dynamická. Statické těleso (podlaha, zeď) má jednoduše nulovou hustotu (nepůsobí na něj gravitace, po náraze ho nic nedokáže odhodit).
  • Těleso (b2Body) se vytváří aplikování metody CreateBody na svět. Jako parametr se uvádí definice tělesa.

Teď si vytvoříme obsah světa. Ve FLA knihovně mám linkage movieclipy Zeme (1000x100 px) a Bedna (60x60 px). Střed grafického tělesa je zároveň středem movieclipu (tj. šířka země je od -500 do 500, výška je od -50 do 50)

Vytvoření tělesa země - podlahy

 var zemeBD:b2BodyDef = new b2BodyDef();            //  definice tělesa
 zemeBD.position.Set(3, 4);                         //  nastavení pozice
 zemeBD.userData = new Zeme();                      //  vytvoření herce, přiřazení k userData
 addChild(zemeBD.userData);                         //  přidání herce na scénu, jsme pořád ve třídě Main, která vychází ze Sprite

 var zemeSD:b2PolygonDef = new b2PolygonDef();      // definice tvaru, mnohoúhelník
 zemeSD.SetAsBox(5, 0.5);                           // rozměry obdélníku jsou poloviční (od středu)
 
 var zeme:b2Body = world.CreateBody(zemeBD);        // vytvoření tělesa ve světě
 zeme.CreateShape(zemeSD);                          // aplikace tvarů na těleso

Vytvoření beden

 var bednaSD = new b2PolygonDef();                  // definice tvaru, mnohoúhelník
 bednaSD.SetAsBox(0.3, 0.3);                        // rozměry bedny
 bednaSD.density = 10;                              // hustota - kg/m^2
 
 var bednaBD = new b2BodyDef();                     // definice tělesa
 
 for(var i:int=0; i<20; i++){                       // cyklem vytvoříme 20 beden

 bednaBD.position.Set(Math.random()*5, Math.random() *(-10) ); // náhodná pozice
 bednaBD.userData= new Bedna();                     // vytvoření herce
 addChild(bednaBD.userData);                        // přidání herce na scénu
 
 var bedna:b2Body = world.CreateBody(bednaBD);      // vytvoření tělesa ve světě 
 bedna.CreateShape(bednaSD);                        // aplikace tvarů na těleso
 bedna.SetMassFromShapes();                         // nastavení hmotnosti (podle tvaru a hustoty)
 
 } 

Nyní to můžeme zkompilovat. Vytvoří se svět a přidají se do něj naše tělesa, která mají námi zadané údaje. Uvidíme však pouze pár MC v levém horním rohu.

Spuštění světa a jeho vykreslování

V této chvíli budeme psát do fukce Update, která se provádí při každém snímku. Potřebujeme udělat krok ve světě, projít všechna tělesa a podle nich nastavit hodnoty všem hercům (MC). userData u b2BodyDef se stala m_userData u b2Body.

public function Update(e:Event):void{

 world.Step(1.0/60.0, 10);    //  krok ve světě dlouhý 1/60 vteřiny, 10 iterací - přesnost vykreslování

 for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next){  //  procházíme seznam těles ve světě
  if (bb.m_userData != null){   //  zjišťujeme, jestli těleso má herce
   bb.m_userData.x = bb.GetPosition().x * 100;                // přiřadíme pozici herci
   bb.m_userData.y = bb.GetPosition().y * 100;
   bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);    // přiřadíme rotaci herci
  }
 }

} 

Výsledek

Zdrojové soubory

Reference k b2Body

Vy teď můžete zkusit napsat kód, kde velikost beden bude náhodná (v nějakém rozmezí). Malá nápověda - userData odkazuje na MovieClip, takže používejte userData.width, userData.height apod.

Také si zkuste hrát s hustotou, třením a elastičností; bednaSD.friction (tření) - 0 až 1; bednaSD.restitution (elastičnost) - 0 - bez odrazu, 1 - odraz do stejné výšky bez ztráty energie, >1 - perpetuum mobile - odrazem dostane energii.

Ivan Kuckir Tvůrce flash her a RIA aplikací, interaktivních webů, začlenění flashe do dalších webových technologií.

E-mail: ivan.kuckir(zavinac)gmail.com | Web: www.ivank.net | ICQ: 303646153 | Skype: van010

Motto: Programování sice může být zajímavé, ale jsou i lepší věci. Třeba nejlepší online hry

Seriál: Box2d - fyzikální svět

Popis fyzikálního engine Box2d pro Flash.

Komentáře k článku  
skvely clanek bbarmann | 27.4.2009 16:43
Velmi pěkné! wilk | 28.4.2009 8:09
Díky ivanK.net | 28.4.2009 20:01
neni co dodat TINYSOFT | 29.4.2009 23:42
dotaz Dritst | 5.5.2009 13:47
AABB ivanK.net | 5.5.2009 16:44
přepočet Dritst | 5.5.2009 21:01
chyba v souboru? Doxxik | 28.5.2009 18:51
Problém s knihovnou MarcoSharper | 23.6.2009 16:28
další články ivanK.net | 12.7.2009 19:33
re blog MarcoSharper | 13.7.2009 7:49

Přihlášení uživatele