Box2D - Klouby a jednoduchá motorka - 4. díl
8.2.2010· Autor: Ivan Kuckir·
Počet komentářů: 6
Po kratší přestávce zde opět máme článek o Box2D. Dnes se podíváme na další užitečnou věc při programování fyzikálních simulací, a to klouby, a nakonec si vytvoříme jedoduchou motorku s ovládáním.
Slovo na úvod
Před tím, než budete pokračovat dále, byste měli být seznámeni s látkou předchozích článků, a to:
Box2D - fyzikální svět - 1. díl
Box2D - první kroky - 2. díl
Box2D - Basketball - 3. díl
Pokud si na ně přesně nevzpomínáte nebo jste si je vlastnoručně neotestovali, doporučuji tak učinit.
Co jsou klouby
Ve fyzikálních enginech se slovem kloub myslí objekt, který má za úkol udržovat vzájemnou polohu dvou těles, a to podle nějakého vztahu. Pěknou demonstraci kloubů můžete vidět na stránkách autora - http://box2dflash.boristhebrave.com/(šipkami přepínáte ukázky). Máme tyto druhy kloubů:
Vzdálenostní kloub (Distance Joint) - b2DistanceJoint

- jeho úkolem je udržovat stanovenou vzdálenost mezi dvěma body ("anchor1" a "anchor2") na tělesech. Představte si ho jako neviditelnou kovovou tyč, která je v místech puntíků připevněná k telesům a může se tam i protáčet.
Rotační kloub (Revolute Joint) - b2RevoluteJoint

- je to vlastně vzdálenostní kloub pro nulovou vzdálenost. Představte si ho tak, že si vystřihnete dva tělesa z papíru, napichnete je na jehlu a můžete s nimi rotovat.
Kladkový kloub (Pulley Joint) - b2PulleyJoint

- v podstatě se jedná o kladku, kterou představují ty dvě čáry na obrázku. Součet jejich délek je buď vždy stejný, nebo můžete stanovit přesný poměr, tj. když jde jedno těleso dolů - druhé jde nahoru. Body "ground1" a "ground2" jsou statické.
Ke všem kloubům
Body "anchor1" a "anchor2" se mohou nacházet i mimo plochu tělesa, budou však stále ve stejné pozici vůči tělesu. Vazby těles ke koubu nejsou "absolutní" a při použití větší síly se dají vychýlit - podle hustoty tělesa. Další klouby a jejich používání můžete nalézt v dokumentaci k Box2D (v angličtině) - http://box2dflash.boristhebrave.com/docs/2.0.2/manual#Joints. V tomto článku si ukážeme použití vzdálenostního kloubu.
Vytváření motorky
Naším plánem je vytvořit motorku ve stylu terénních 2D závodů, kde s motorkou skáčete přes překážky, děláte salta apod. Jako tělo motorky nám poslouží čtyřúhelník a jako kola použijeme dvě kružnice. Mezi nimi vytvoříme vzdálenostní klouby (červené čáry, viz obrázek níže):

Základní AS soubor
Vytvoříme si následující AS soubor. Řádky, které nejsou okomentovány, by měly být jasné z předchozích článků.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
public class Main extends Sprite
{
public var world:b2World;
public var ground:b2Body; // těleso země
public var wheelF:b2Body; // přední kolečko - "front"
public var wheelB:b2Body; // zadní kolečko - "back"
public var motorBody:b2Body; // tělo motocyklu
public var jointB1:b2Joint; // první zadní kloub
public var jointB2:b2Joint; // druhý zadní kloub
public var jointF1:b2Joint; // první přední koub
public var jointF2:b2Joint; // druhý přední kloub
public var up:int = 0; // signalizátor nahoru/dolů
public var right:int = 0; // signalizátor doprava/doleva
public var rightSide:Boolean = true; // zda je motocykl otočený doprava
public function Main()
{
addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
addEventListener(Event.ADDED_TO_STAGE, addListeners);
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);
var gravity:b2Vec2 = new b2Vec2 (0.0, 10.0);
var doSleep:Boolean = true;
world = new b2World(worldAABB, gravity, doSleep);
createGround(); // funkce pro vytvoření terénu
//////////////////////////////////////
}
public function addListeners(e:Event):void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
}
public function createGround():void
{
}
public function onKeyDown(e:KeyboardEvent):void
{
}
public function onKeyUp(e:KeyboardEvent):void
{
}
public function Update(e:Event):void
{
world.Step(1.0/60.0, 10);
for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next)
{
if (bb.m_userData != null && !bb.IsSleeping())
{
bb.m_userData.x = bb.GetPosition().x * 100;
bb.m_userData.y = bb.GetPosition().y * 100;
bb.m_userData.rotation = (bb.GetAngle() * (180/Math.PI))%360;
}
}
}
}
}
Jako jednoduché cvičení si zkuste do funkce createGround dopsat vytvoření libovolného terénu - viz minulé články. Můj terén, který vidíte v ukázce a můžete si ho i stáhnout, je dělaný přes vkládání trojúhelníků podle souřadnic vrcholů uložených v poli. Vy si můžete vymyslet vlastní systémy a s nimi vytvářet dokonale propracované terény.
Motorka
Další kód budeme psát do konstruktoru Main na konec (tam, kde jsou lomítka). Vytvoříme si kolečka:
var wheelSD = new b2CircleDef(); // definice tvaru kolečka
wheelSD.radius = 0.25; // poloměr kolečka
wheelSD.density = 15; // hustota
wheelSD.friction = 1.5; // tření
wheelSD.restitution = 0.5; // elastičnost ("odráživost")
var wheelBD:b2BodyDef = new b2BodyDef(); // definice těla kola
wheelBD.angularDamping = 2; // tlumení rotace
wheelBD.position.Set(1.02,0.48); // pozice prvního kolečka
wheelBD.userData = new Wheel(); // vytvoření herce (připraven v knihovně - linkage)
addChild(wheelBD.userData); // přidání herce na scénu
wheelF = world.CreateBody(wheelBD); // vytvoření tělesa ve světě podle definice
wheelF.CreateShape(wheelSD); // vytvoření jeho tvaru
wheelF.SetMassFromShapes(); // nastavení hmotnosti podle tvaru
// to same se zadním kolem
wheelBD.position.Set(-0.12,0.47);
wheelBD.userData=new Wheel();
addChild(wheelBD.userData);
wheelB = world.CreateBody(wheelBD);
wheelB.CreateShape(wheelSD);
wheelB.SetMassFromShapes();
Kolečka už máme, teď si vytvoříme tělo motocyklu (čtyřúhelník)
var motorBodyBD:b2BodyDef = new b2BodyDef(); // definice tělesa
motorBodyBD.position.Set(0.43, 0.18); // pozice ve světě
motorBodyBD.linearDamping = 0.2; // tlumení pohybu
motorBodyBD.userData = new MotorBody(); // vytvoření herce (linkage MC v knihovně)
addChild(motorBodyBD.userData); // přidání herce na scénu
var motorBodySD = new b2PolygonDef(); // definice tvaru (mnohoúhelník)
motorBodySD.density = 55; // hustota tělesa
motorBodySD.vertexCount = 4; // počet vrcholů
motorBodySD.vertices[0].Set(-0.45, -0.12); // nastavení pozic vrhcolů
motorBodySD.vertices[1].Set( 0.42, -0.18); // ....
motorBodySD.vertices[2].Set( 0.14, 0.23);
motorBodySD.vertices[3].Set( -0.09, 0.25);
motorBody = world.CreateBody(motorBodyBD); // vytvoření tělesa ve světě podle definice
motorBody.CreateShape(motorBodySD); // vytvoření jeho tvaru
motorBody.SetMassFromShapes(); // nastavení hmotnosti podle tvaru
Už teď to můžeme spustit. Uvidíme tělo a kolečka, jak padají dolů. Zatím nejsou nijak spojeny. Proto přidáme 4 klouby (červené čáry - viz obrázek výše).
Vytvoření kloubů se skládá ze 3 částí:
- vytvoření definice kloubu - jednoduše se vytvoří nová instance třídy - new b2xxxxJointDef();
- inicializace - zavolá se metoda, ve které se předají 2 tělesa, mezi kterými má být kloub + globální souřadnice bodů na tělesech, ke kterým se má koub připojit
- vytvoření kloubu do světa - zavolá se metoda světa CreateJoint (podobně jako CreateBody()).
var jointDef:b2DistanceJointDef = new b2DistanceJointDef()
jointDef.Initialize(wheelF, motorBody, wheelF.GetPosition(), new b2Vec2(.75, .05));
jointF1 = world.CreateJoint(jointDef);
jointDef.Initialize(wheelF, motorBody, wheelF.GetPosition(), new b2Vec2(.62, .18));
jointF2 = world.CreateJoint(jointDef);
jointDef.Initialize(wheelB, motorBody, wheelB.GetPosition(), new b2Vec2(.33, .28));
jointB1 = world.CreateJoint(jointDef);
jointDef.Initialize(wheelB, motorBody, wheelB.GetPosition(), new b2Vec2(.36, .35));
jointB2 = world.CreateJoint(jointDef);
Určitě jste si všimli, že většina souřadnic jsou celkem konkrétní čísla. Tato čísla jsem si nevymyslel - jednoduše jsem si načetl obrázek výše do Flashe, umístil ho středem motocyklu do levého horního rohu a ostatní jsouřadnice jsem okoukal podle flashových pravítek.
Když to teď spustíme, dostaneme motorku, která má k sobě připojená kolečka a padá na zem (pokud jste si ji vytvořili). Naše první motorka je na světě!
Ovládání
Teď si dopíšeme listenery tlačítek.
public function onKeyDown(e:KeyboardEvent):void
{
switch(e.keyCode) // zkoušíme hodnotu kódu tlačítka:
{
case 38: up = 1; break; // šipka nahoru - nastavíme up kladné
case 40: up =-1; break; // šipka dolů - nastavíme up záporné
case 39: right = 1; break; // šipka doprava- nastavíme right kladné
case 37: right =-1; break; // šipka doleva - nastavíme right záporné
case 32: rightSide = !rightSide; // mezerník - změníme rightSide na opačnou hodnotu
motorBody.m_userData.scaleX *= -1; break; // a vertikálně převrátíme herce těla motorky
case 74: motorBody.ApplyImpulse(new b2Vec2(0, -70), motorBody.GetWorldCenter()); break; // "J" - skok do vzduchu
}
}
public function onKeyUp(e:KeyboardEvent):void
{
switch(e.keyCode)
{
case 38: up = 0; break; // puštění šipky nahoru - vynulujeme up
case 40: up = 0; break; // pustění šipky dolů - to samé
case 39: right = 0; break; // puštění šipky vpravo - vynulujeme right
case 37: right = 0; break; // puštění šipky vlevo - to samé
}
}
Také přidáme patřičnou akci do Update (pod for cyklus) a na závěr si můžeme trošku pohrát s grafikou (herců nebo prostředí), jako jsem si hrál já :-).
if(up!=0) // pokud je zmáčknuté nahoru nebo dolů
{
if(rightSide) wheelB.ApplyTorque(up*26); // pokud je motorka natočená vpravo, nastavíme moment síly na zadní (levé) kolečko
else wheelF.ApplyTorque(up*-26); // jinak nastavíme na přední (pravé)
}
if(right!=0) motorBody.ApplyTorque(right*35); // pokud je zmáčknutá šípka vpravo nebo vlevo, aplikujeme moment síly na tělo motorky
this.x = 400 - motorBody.m_userData.x; // a nakonec přesuneme celý tento objekt podle pozice motorky, aby zůstala uprostřed
A můžeme jet!
Stáhnout zdrojový kód
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.