Box2D: Un motore fisico opensource multipiattaforma
Maurizio Moriconi
CTO presso MobilesoftMobile Developer
Co-founder Pixmapbrothers
Ubuntu member
bugman79 on Twitter
Box2D
Motore fisico 2d
Opensource (licenza zlib)Creato da Erin Catto
(Blizzard Entertainment)Scritto in C++ Multi piattaforma
Usato da molti giochi tra cui:Angry BirdsRolandoCrayon Physics Deluxe
Alcune risorse
Sito ufficiale: http://www.box2d.org/
Codice sorgente: http://code.google.com/p/box2d/
Documentazione online:http://www.box2d.org/manual.html
Forum ufficiale: http://box2d.org/forum/
LIVE: Installazione su iOS
Motore Fisico
Può essere visto come un sistema di animazione (videogiochi)
Permette il mapping tra “sprite” ed oggetti fisici
Oggetto fisico: rigid bodies (corpi rigidi)
- Dynamic (Dinamici)
- Static (Statici)
Motore Fisico in Box2D
World
Definisce la gravità (gravity)
Muove i corpi (step)
Intercetta le collisioni (contact listener)
Contiene i vari bodies (corpi fisici)
Motore Fisico in Box2D
BodyPosition / Rotation
Density / Mass (Densità / Massa)Friction (Attrito nel contatto)Restitution (Fattore di rimbalzo)
Contengono un puntatore void per dati aggiuntivi (User Data)
Possono avere uno o più Fixture
Motore Fisico in Box2D
ShapeArea di un bodyPuò essere un cerchio, un rettangolo o un poligonoSono usati per gestire le collisioni tra corpi
FixtureCollega una Shape con un BodyCollision Filtering (permette di decidere se uno shape deve collidere o
meno)Aggiunge al body le proprietà fisiche:
• Density• Friction• Restitution
Motore Fisico in Box2D
JointConnettono più corpiLimitano il loro movimento in vari modi:
Motore Fisico in Box2D
Le animazioni dei corpi dinamici avvengono tramite:
Force (Forze)
Impulse (Impulsi)
Torque (Momento di torsione)
Unità di misura
MKS (meters-kilogram-second)
Box2D lavora con i numeri in virgola mobile!!!
Ottimizzato per lavorare bene con oggetti che si muovono tra 0.1 e 10 metri
Gli oggetti statici possono essere grandi sopra i 50 metri senza problemi.
Box2D usa i radianti per gli angoli.
Per iniziare, Conquest the World!b2Vec2 gravity(0.0f, -10.0f);
bool doSleep = true;
b2World world(gravity, doSleep);
b2Vec2 : vettore a 2 dimensioni (in questo caso la gravità)
doSleep: un body fermo può passare allo stato sleepun body in sleep non richiede alcun calcolo nella simulazione
fisicaun body torna attivo appena “toccato” o su richiesta (awake)
Creazione di un body
1. Definire un body con una posizione
2. Usare l'oggetto world per creare un body
3. Definire uno shape
4. Definire la fixture con lo shape aggiungendo friction, density...
5. Creare la fixture sul body
Body statici: Ground Box
1. Definire un body con una posizioneb2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, -10.0f);
2. Usare l'oggetto world per creare un bodyb2Body* groundBody = world.CreateBody(&groundBodyDef);
Di base un body è creato come statico: – Non fa collisione con altri body statici– È inamovibile– statico per Box2D → Massa = 0
Body statici: Ground Box
3. Definire uno shapeb2PolygonShape groundBox;
groundBox.SetAsBox(50.0f, 10.0f);
In questo caso un PolygonShape
SetAsBox prende come parametri le grandezze / 2
Quindi nell'esempio il box è 100x20 (metri si suppone)
5. Creare la fixture sul bodygroundBody->CreateFixture(&groundBox,0);
L'oggetto b2Shape “è dentro” la fixture!!!
Body Dinamici
1. Definire un bodyb2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0f, 4.0f);
In questo caso si specifica che è Dinamico!
2. Usare l'oggetto world per creare un bodyb2Body* body = world.CreateBody(&bodyDef);
Body Dinamici
3. Definire uno shapeb2PolygonShape dynamicBox;
dynamicBox.SetAsBox(1.0f, 1.0f);
4. Definire la fixture con lo shape aggiungendo friction, density...
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
Definiamo la fixture con densità pari a 1 e attrito pari a 0.3
5. Creare la fixture sul bodybody->CreateFixture(&fixtureDef);
Simulating the World!
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
world.Step(timeStep, velocityIterations, positionIterations);
Time Step 60Hz (1/60 di secondo)
Iterator Sono i cicli in cui Box2d itera per calcolare posizione e velocitàUn valore di 10 è suggeritoDa decidere come compromesso tra velocità e precisione
LIVE: Hello Box2D
Rendering
Il motore fisico da solo non basta...
Mappare oggetti fisici ad oggetti “reali”
1) UIKit
2) OpenGL ES
3) Altro...
Rendering con UIKit
Physics 101 – UIKit app with Box2D for Gravity
http://www.cocoanetics.com/2010/05/physics-101-uikit-app-with-box2d-for-gravity/
Rendering con UIKit
1) Gestione di un sistema di coordinate Box2d → UIKit e viceversa
2) Creare rappresentazione fisica per ogni view
3) Impostare un timer per :Muovere il motore fisicoAggiornare posizione ed angolo delle nostre view
Sistema di coordinate
Posizione di partenza (0,0)UiKit in alto a sinistraBox2d in basso a sinistra
Unità di misura: Pixel vs Metri!!
#define PTM_RATIO 16
16 pixel equivalgono ad 1 metro
Rappresentazione fisica
DimensioniCGPoint boxDimensions = CGPointMake(
physicalView.bounds.size.width/PTM_RATIO/2.0,physicalView.bounds.size.height/PTM_RATIO/2.0 );
PosizioneCGPoint p = physicalView.center;
bodyDef.position.Set(
p.x/PTM_RATIO,
(480.0 – p.y)/PTM_RATIO );
UserData bodyDef.userData = physicalView;
Timer e Step
tickTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(tick:) userInfo:nil repeats:YES];
Quindi un timer che chiama la funzione tick all'infinito.
Mentre i parametri per l'iterator sono:
int32 velocityIterations = 8;
int32 positionIterations = 1;
world->Step(1.0f/60.0f, velocityIterations, positionIterations);
for(b2Body* b=world->GetBodyList(); b; b=b->GetNext())
{
if (b->GetUserData() != NULL)
{
UIView *oneView = (UIView *)b->GetUserData();
CGPoint newCenter = CGPointMake(
b->GetPosition().x * PTM_RATIO,
self.view.bounds.size.height - b->GetPosition().y * PTM_RATIO);
oneView.center = newCenter;
CGAffineTransform transform = CGAffineTransformMakeRotation(- b->GetAngle());
oneView.transform = transform;
}
}
LIVE: Rendering con UIKit
Debug Draw
Classe da utilizzare per debug
Creare una classe che estende b2DebugDraw:class DebugDraw : public b2DebugDraw
{
public:
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);
void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);
….
};
Debug Draw
Attivare i flags:
m_world->SetDebugDraw(&m_debugDraw);
int32 flags = 0;
flags += 1 * b2DebugDraw::e_shapeBit;
flags += 1 * b2DebugDraw::e_jointBit;
flags += 1 * b2DebugDraw::e_coreShapeBit;
flags += 1 * b2DebugDraw::e_aabbBit;
flags += 1 * b2DebugDraw::e_obbBit;
flags += 1 * b2DebugDraw::e_pairBit;
flags += 1 * b2DebugDraw::e_centerOfMassBit;
m_debugDraw.SetFlags(flags);
LIVE: Esempi vari
Altre caratteristiche
Gestione dei contatti (Contact Listener)Applicazione di forze, impulsiJoint
Provare il TestBed !!!
Cocos 2D
Progetto opensourceScritto in Objective-CIntegra i motori fisici Box2D e ChipmunkUsa OpenGL ES 1.0Supporto per videogiochi:
Suono e musicaSistema particellareTile Map e parallasseText renderingGestione menùGestione highscore….
Altre piattaforme???
- C# : Box2DX, Box2D.XNA,
- JAVA : Jbox2D
- Delphi: Box2D Delphi
- Javascript : Box2DJS, box2dweb
- FLASH : Box2DFlash
- DS : Box2D for DS
The End