domingo, 25 de julio de 2021

libGDX: Colisiones

En este tutorial vamos a hacer una modificación al código del tutorial anterior para detectar colisiones entre los objetos. 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.

    

0 comments:

Publicar un comentario

Entradas populares