libGDX: Colisiones
En este tutorial vamos a hacer una modificación al código del tutorial anterior para detectar colisiones entre los cuerpos. Para hacerlo interesante cuando 2 objetos del mismo tipo (caja o pelota) colisiones los vamos a eliminar del mundo.
Antes de comenzar recuerda que puedes descargar el código completo en Github y si lo prefieres puedes ver el video tutorial de este articulo.
También puedes correr la aplicación de este tutorial en tu navegador.
Para iniciar en la clase GameObject
necesitamos saber el estado actual del objeto, por ejemplo puede ser normal o golpeado. Definimos los dos estados y también creamos una variable state para guardar el estado actual:
static private class GameObject {
//...más código
static final int STATE_NORMAL = 0;
static final int STATE_HIT = 1;
int state;
}
También creamos una función dentro de GameObject
que vamos a llamar cuando 2 objetos del mismo tipo colisionan:
static private class GameObject {
//...más código
public void hit() {
state = STATE_HIT;
}
}
Ahora vamos a crear una clase nueva que yo voy a llamar CollisionListener
que sirve para detectar cuando los objetos en Box2D tiene contacto. En la función beginContact
vamos a crear una condición para revisar si 2 objetos del mismo tipo (caja o pelota) tuvieron contacto y si la condición es verdadera llamamos a la función hit
.
static private class CollisionListener implements ContactListener {
@Override
public void beginContact(Contact contact) {
Body bodyA = contact.getFixtureA().getBody();
Body bodyB = contact.getFixtureB().getBody();
if (bodyA.getUserData() instanceof GameObject && bodyB.getUserData() instanceof GameObject) {
GameObject gameObjectA = (GameObject) bodyA.getUserData();
GameObject gameObjectB = (GameObject) bodyB.getUserData();
if (gameObjectA.type == gameObjectB.type) {
gameObjectA.hit();
gameObjectB.hit();
}
}
}
}
Básicamente cada vez que dos objetos tienen contacto se llama la función beginContact
con los cuerpos (Body) de los dos objetos. Con los cuerpos podemos obtener la instancia del tipo GameObject
y podemos comparar si son del mismo tipo.
Nota
En este momento no hemos eliminado los cuerpos del mundo. Es importante no eliminar los cuerpos en este momento porque el mundo está evaluando la física del juego, y eliminar un cuerpo podría tener resultados inesperados
La eliminación de los cuerpos la vamos a realizar en la función update
. Vamos a iterar en cada cuerpo y en caso de que el estado sea STATE_HIT
lo vamos a eliminar del mundo:
@Override
public void update(float delta) {
//...más código
oWorld.step(delta, 8, 6);
oWorld.getBodies(arrBodies);
for (Body body : arrBodies) {
if (oWorld.isLocked()) continue;
if (body.getUserData() instanceof GameObject) {
GameObject obj = (GameObject) body.getUserData();
if (obj.state == GameObject.STATE_HIT) {
arrGameObjects.removeValue(obj, true);
oWorld.destroyBody(body);
}
}
}
//...más código
}
Como puedes ver, la eliminación de los cuerpos es después de la función oWorld.step
en otras palabras después que todas las evaluaciones físicas del juego se han completado.