Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
© 2012-2013 Depto. Ciencia de la Computación e IA
Videojuegos
Sesión 4: Motor de físicas
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Puntos a tratar• Motor Box2D• Objetos de Box2D• Tipos de cuerpos• Unidades de medida• Simulación física• Detección de colisiones• Physics Editor
2
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Motor de físicas Box2D• Físicas de cuerpos rígidos• Escrito en C++• Se incluye en la mayoría de motores• AndEngine, Cocos2D, libgdx
3
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Conceptos de Box2D
4
Body Cuerpo rígido. Puede ser estático, cinemático, o dinámico
Fixture Fija las propiedades de un cuerpo, incluyendo su forma
Shape Define la forma de un cuerpo (círculo o polígono)
Constraint Limita los grados de libertad de un objeto
Joint Define una unión de diferentes cuerpos
World Simulación del mundo 2D. Contiene un conjunto de cuerpos
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Mundo de Box2D• Se encarga de realizar la simulación física
• Podemos añadir al mundo diferentes cuerpos rígidos
• Se crea con el vector de gravedad a aplicar• La gravedad se indica mediante un vector 2D (x, y)• El segundo parámetro nos permite optimizar el rendimiento,
evitando que se simulen los cuerpos inactivos si es true
• Podemos cambiar la gravedad con SetGravity
5
b2Vec2 gravity;gravity.Set(0, -‐10);b2World *world = new b2World(gravity);
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Tipos de cuerpos en Box2D
6
Estático
CinemáticoDinámico
• Usa el sistema métrico (m, kg)• Debemos fijar ratio de conversión píxeles-metros• Optimizado para manejar objetos de 1 metro
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Unidades de medida en Box2D
7
b2BodyDef bodyDef;bodyDef.type = b2_dynamicBody; bodyDef.position.Set(x / PTM_RATIO, y / PTM_RATIO); b2Body *body = world-‐>CreateBody(&bodyDef); b2PolygonShape bodyShape;bodyShape.SetAsBox((width/2) / PTM_RATIO, (height/2) / PTM_RATIO); body-‐>CreateFixture(&bodyShape, 1.0f);
PTM_RATIO = 32width = 32 (1m)height = 64 (2m)
32 px1 m
64 px2 m
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Límites del escenario• Podemos crearlos como objetos estáticos de tipo arista
8
b2BodyDef limitesBodyDef;limitesBodyDef.position.Set(x, y); b2Body *limitesBody = world-‐>CreateBody(&limitesBodyDef);b2EdgeShape limitesShape;b2FixtureDef fixtureDef;fixtureDef.shape = &limitesShape; limitesShape.Set(b2Vec2(0.0f / PTM_RATIO, 0.0f / PTM_RATIO), b2Vec2(width / PTM_RATIO, 0.0f / PTM_RATIO));limitesBody-‐>CreateFixture(&fixtureDef); limitesShape.Set(b2Vec2(width / PTM_RATIO, 0.0f / PTM_RATIO), b2Vec2(width / PTM_RATIO, height / PTM_RATIO));limitesBody-‐>CreateFixture(&fixtureDef); limitesShape.Set(b2Vec2(width / PTM_RATIO, height / PTM_RATIO), b2Vec2(0.0f / PTM_RATIO, height / PTM_RATIO));limitesBody-‐>CreateFixture(&fixtureDef); limitesShape.Set(b2Vec2(0.0f / PTM_RATIO, height / PTM_RATIO), b2Vec2(0.0f / PTM_RATIO, 0.0f / PTM_RATIO));limitesBody-‐>CreateFixture(&fixtureDef);
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Simulación física• En cada iteración del ciclo del juego debemos actualizar la
simulación del mundo físico• Debemos proporcionar el delta time en la actualización
9
// Ejecuta la simulaciónworld-‐>Step(delta, 6, 2);world-‐>ClearForces(); // Lee datos de los cuerpos en la simulación físicab2Vec2 pos = body-‐>GetPosition();CGFloat rot = -‐1 * CC_RADIANS_TO_DEGREES(b-‐>GetAngle()); sprite.position = ccp(pos.x*PTM_RATIO, pos.y*PTM_RATIO);sprite.rotation = rot;
Conviene acortarlo
Iteraciones posición
Iteraciones velocidad
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Datos de usuario de los cuerpos• Podemos asignar datos de usuarios genéricos a los cuerpos• Útil para adjuntar el sprite asociado al cuerpo
• El cuerpo de Box2D sólo realiza simulación física• Nosotros debemos mostrarlo en pantalla mediante un sprite• Esto lo haremos tras la actualización del mundo
10
bodyDef.userData = sprite;
CCSprite *sprite = (CCSprite *)body-‐>GetUserData();b2Vec2 pos = body-‐>GetPosition();CGFloat rot = -‐1 * CC_RADIANS_TO_DEGREES(b-‐>GetAngle()); sprite.position = ccp(pos.x*PTM_RATIO, pos.y*PTM_RATIO);sprite.rotation = rot;
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Detección de colisiones• Podemos definir listener de contacto (ContactListener)
11
class MiContactListener : public b2ContactListener { public: MiContactListener(); ~MiContactListener(); // Se produce un contacto entre dos cuerpos virtual void BeginContact(b2Contact* contact); // El contacto entre los cuerpos ha finalizado virtual void EndContact(b2Contact* contact); // Se ejecuta antes de resolver el contacto. // Podemos evitar que se procese virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold); // Podemos obtener el impulso aplicado sobre los cuerpos en contacto virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse); };
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Velocidad de impacto
• WorldManifold da información sobre los puntos de contacto
12
void MiContactListener::BeginContact(b2Contact* contact) { b2Body *bodyA = contact.fixtureA-‐>GetBody(); b2Body *bodyB = contact.fixtureB-‐>GetBody(); // Obtiene el punto de contacto b2WorldManifold worldManifold; contact-‐>GetWorldManifold(&worldManifold); b2Vec2 point = worldManifold.points[0]; // Calcula la velocidad a la que se produce el impacto b2Vec2 vA = bodyA-‐>GetLinearVelocityFromWorldPoint(point); b2Vec2 vB = bodyB-‐>GetLinearVelocityFromWorldPoint(point); float32 vel = b2Dot(vB -‐ vA, worldManifold.normal); ...}
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Impulso durante el contacto
• Nos informa de la fuerza ejercida entre los cuerpos mientras dura el contacto
13
void MiContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { b2Body *bodyA = contact.fixtureA-‐>GetBody(); b2Body *bodyB = contact.fixtureB-‐>GetBody(); float impulso = impulse-‐>GetNormalImpulses()[0];}
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Physics Editor• En código podemos definir formas básicas• Es difícil definir figuras complejas• Podemos utilizar herramientas como Physics Editor
14
http://www.codeandweb.com/physicseditor
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Opciones de Physics Editor• Podemos cargar sprites y obtener su contorno automáticamente• Existe una herramienta de tipo “varita mágica”
• Debemos cargar la versión normal (no retina)• Podemos especificar• Ratio points-to-meters• Anchor point del sprite• Propiedades de la fixture (restitution, friction, etc)• Formato de salida
• Como formato de salida seleccionaremos Box2D genérico• Exporta la forma como un fichero plist• Podemos cargar dicho fichero desde Cocos2D
15
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
Carga de formas en Cocos2D• Debemos copiar en el proyecto la librería de Physics Editor• Se puede encontrar en el instalador del programa
• Cargamos en contenido del fichero en la caché de formas
• Asignamos una fixture de la caché a un cuerpo• Se debe proporcionar el nombre del sprite en el fichero
• No es necesario definir la fixture en código
16
[[GB2ShapeCache sharedShapeCache] addShapesWithFile:@"formas.plist"];
b2Body *body = ... // Inicializar body [[GB2ShapeCache sharedShapeCache] addFixturesToBody:body forShapeName:@"roca"];
Experto en Desarrollo de Aplicaciones para Dispositivos Móviles
Videojuegos © 2012-2013 Depto. Ciencia de la Computación e IA Motor de físicas
¿Preguntas...?
17