BOX2D per iPhone: ovvero la fisica dei corpi grazie a BugMan !
by Stefano LoduBox2d è un simulatore di corpi rigidi in 2D sviluppato in C++. E’ molto utile perché permette in poche righe di creare un motore fisico e quindi al posto di crearsi tutte quelle routine per l’animazione degli oggetti lasciamo ad Dott. Isaac Newton di farlo per noi attraverso le regole della Fisica
Caratteristiche del motore fisico:
Collision
- Continuous collision detection.
- Contact callbacks: add, persist, remove.
- Convex polyons and circles.
- Multiple shapes per body
- One-shot contact manifolds
- Incremental sweep-and-prune broadphase
- Efficient pair management
- Fast broadphase AABB queries
- Collision groups and categories
Physics
- Continuous physics with time of impact island solver.
- Persistent body-joint-contact graph
- Island solution and sleep management
- Contact, friction, and restitution
- Stable stacking with a linear-time solver
- Revolute, prismatic, distance, pulley, gear, and mouse joints
- Joint limits, motors, and friction
- Momentum decoupled position correction
- Fairly accurate reaction forces/impulses
System
- Small block and stack allocators
- Centralized tuning parameters
- Highly portable C++ with no use of STL containers
Testbed
- OpenGL with Freeglut
- Graphical user interface with GLUI
- Easily switch between tests using GUI
- Test framework for easily adding new tests
- Mouse picking and the bomb!
- VC8 project files
In particolare il TestBed ha anche un progetto per Xcode così da poter provare su Macosx
i vari esempi (sono tanti e tutti documentatissimi).
Dicevamo che è scritto in C++, in particolare la maggior parte delle funzioni e dei tipi iniziano con il prefisso b2.
E’ facilmente integrabile in qualunque progetto per Iphone, vediamo brevemente quali sono i passi da compiere per crearsi un progetto che abbia un motore Box2d al suo interno.
1) Scaricarsi il codice sorgente di Box2d da http://sourceforge.net/projects/box2d
Attualmente la versione è la 2.0.1 (13 Aprile 2008)
2) Scompattare il tutto su una cartella
3) Creare o aprirsi un progetto Xcode (magari uno che abbia una vista OpenGLEs)
4) Copiare (anche tramite drag & drop) la cartella Source dentro il nostro progetto Xcode
5) Nella propria view includere l’header di Box2d
#include “Box2D.h”
6) Rinominare il file della view in .mm (per mischiare C++ e objective C)
7) Inizialiare un mondo prima di procedere con l’attivazione della vista OpenGLES
Qualcosa di simile:
Da qualche parte definisco le variabili:
b2AABB worldAABB;
b2World *m_world;
E poi l’init del mondo è :
// inizializzo le coordinate del mondo
worldAABB.lowerBound.Set(-100.0f, -100.0f);
worldAABB.upperBound.Set(100.0f, 100.0f);
// Definisco il vettore di gravità
b2Vec2 gravity(0, -9.81f);
// Do we want to let bodies sleep?
bool doSleep = true;
// Costruisco il mondo
m_world= new b2World(worldAABB, gravity, doSleep);
// Definisco il corpo ground (terreno)
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, -15.0f);
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
b2Body* groundBody = m_world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2PolygonDef groundShapeDef;
// The extents are the half-widths of the box.
groundShapeDef.SetAsBox(50.0f, 10.0f);
// Add the ground shape to the ground body.
groundBody->CreateShape(&groundShapeDef);
8 ) Nel main loop (se vogliamo la DrawView della nostra vista OpenGLES) faccio avanzare
la fisica del mondo:
float32 timeStep = 1.0f / 60.0f;
int32 iterations = 10;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
m_world->Step(timeStep, iteration);
(timeStep può essere benissimo animationInterval che usiamo per la view)
9) a questo punto si possono creare oggetti e usando una draw adatta disegnarli per vedere cosa
succede, per esempio se mi creo un cerchio in questo modo:
posX e posY sono la posizione del cerchio
m_body è un oggetto (body) inizializzato così: b2Body *m_body;
m_world è il nostro mondo creato in precedenza
ang è l’angolo di rotazione (in radianti)
// Define the dynamic body. We set its position and call the body
b2BodyDef bodyDef;
bodyDef.position.Set(posX, posY);
bodyDef.angle = ang; // the body’s angle in radians.
//bodyDef.linearDamping = 0.0f;
//bodyDef.angularDamping = 0.01f;
//bodyDef.isBullet = false;
bodyDef.angularDamping = 0.02f;
m_body = m_world->CreateBody(&bodyDef);
// Define box shape for our dynamic body.
b2CircleDef circleDef;
// Set the box density to be non-zero, so it will be dynamic.
circleDef.density = 1.0f;
// Override the default friction.
circleDef.friction = 0.3f;
// Add the shape to the body.
m_body->CreateShape(&circleDef);
// Now tell the dynamic body to compute it’s mass properties base
// on its shape.
m_body->SetMassFromShapes();
Se vedete il codice al body va associato uno shape che sarà poi la forma che permette di controllarne la fisica, le collisioni e molto altro.
Se poi vogliamo disegnare questo oggetto procediamo in opengles a disegnare uno Sprite (c’e’ l’esempio dell’SDK che puo’ tornare utile) con la posizione corretta che prendiamo in questo modo:
// Vettore posizione del body:
b2Vec2 position = m_body->GetPosition();
// X sarà position.x e Y sarà position.y
// Angolo di rotazione del body
float32 angle = m_body->GetAngle();
Una volta presi questi parametri il disegno dell’oggetto è semplicemente tuto codice openGLES:
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, spriteTexture);
if(m_isBlend) {
// Set a blending function to use
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Enable blending
glEnable(GL_BLEND);
}
glTranslatef(position.x, position.y, 0.0f);
glRotatef(angle*(180/b2_pi), 0.0, 0.0, 1.0f);
glVertexPointer(2, GL_FLOAT, 0, m_vertices);
glEnableClientState(GL_VERTEX_ARRAY);
// va tolto il colore se è textured!!! SI MA LO FACCIO SU SETTEXTURE
glColor4f(m_color_r, m_color_g, m_color_b, 1.0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if(m_isBlend) {
glDisable(GL_BLEND);
}
if(m_isTextured) {
glDisable(GL_TEXTURE_2D);
}
glPopMatrix();
Per voi BugMan e un caloroso ringraziamento da Sir. Lodux !






One Comment. Subscribe to this post comments or trackback.
giugno 23rd, 2009
Grazie Mille per i consigli !!! scrivete qualcosa anche su chipmunk