Saltar al contenido principal

Colisiones

Youtube video player

Youtube video player

info

Prueba el demo en tu navegador y descarga el código fuente de todos los tutoriales en GitHub.

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.

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.

info

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.