Développement d’un jeu de plateforme 2D avec libGdx en MVC – Partie 2 – Animation

Pour cette deuxième partie du jeu Bob Game avec libGdx, vous devrez au préalable avoir réalisé la première partie. Il y aura beaucoup de choses couverte dans les articles suivants, je vais essayer de les décomposer dans des tailles plus modestes. Nous avons démarré avec un monde de base et Bob qui glisse de gauche à droite lorsque les flèches sont appuyées sur le clavier ou encore en touchant l’écran. Ainsi dans cette partie nous allons animer Bob lorsqu’il se déplace.

Animation du personnage

Pour animer Bob, nous allons utiliser la technique la plus simple appelée animation de sprite . L’animation n’est rien de plus qu’une séquence d’images affichées à un intervalle défini pour créer l’illusion du mouvement. La séquence d’images suivante est utilisé pour créer une animation de course. running-bob Ces images ont été prises à partir de l’article original. Pour créer des animations c’est est assez simple. Nous voulons afficher chaque image pendant un certain laps de temps, puis passer à l’image suivante. Quand nous sommes arrivés à la fin de la séquence on recommence. C’est ce qu’on appelle la boucle. Nous devons déterminer la durée d’une trame qui est le laps de temps durant lequel la trame sera affichée. Disons que nous rendons le jeu à 60 FPS, ce qui signifie que nous rendons une image tous les 1/60 = 0,016 s. Nous avons seulement 5 trames pour animer une étape complète. Compte tenu d’un athlète typique de la cadence de 180, nous pouvons travailler sur combien de temps nous montrons chaque cadre pour afficher une course réaliste.

Les mathématiques derrières la course

Une cadence de 180 signifie 180 pas par minute. Pour calculer le nombre de pas par seconde nous avons 180/60 = 3. Donc, à chaque seconde, nous avons besoin de prendre 3 étapes. Nos 5 images représentent un pas complet, donc nous devons montrer 3 * 5 = 15 images par seconde pour simuler course d’un athlète professionnel. Notre durée de trame sera de 1/15 = 0,066 secondes. C’est 66 ms.

Optimiser les images

Avant de les ajouter au jeu, nous allons optimiser les images. Actuellement, le projet a des images distinctes en format PNG dans le répertoire « assets/images". Nous utilisons actuellement block.png et bob_01.png. Il y a quelques images supplémentaires, nommément bob_02 à 06.png. Ces images représentent la séquence d’animation. Parce sous le capot libGdx utilise OpenGL, ce n’est pas optimal de donner des lots d’images comme textures pour travailler avec le framework. Ce que nous allons faire, c’est de créer un Texture Atlas. Un atlas de texture est composé de deux éléments soient une image qui est assez grande pour contenir plusieurs images du jeu et un descripteur qui contient le nom de chaque image, la position de l’image dans l’atlas et la taille. Les images individuelles sont appelées régions d’atlas. S’il y a beaucoup d’images, l’atlas peut avoir plusieurs pages. Chaque page est chargée dans la mémoire comme une image unique et les régions sont utilisées sous forme d’images individuelles. L’utilisation d’un atlas de texture optimise l’application, car elle va charger plus rapidement et se s’exécutera plus en douceur. LibGdx offre un outil nommé TexturePacker dans la librairie gdx Tools qui permet de générer un atlas de texture. On peut l’utiliser dans java en codant une petite application ou encore en ligne de commande. Pour l’exécuter en codant une petite application , il suffit de suivre l’annexe suivant. Les fichiers d’images de bob sont disponibles ici.
  1. Générez le package à l’aide des images fournies
  2. Créez un dossier « images/textures« 
  3. Ajoutez les deux nouveaux fichiers qui ont été créés à l’aide de TexturePacker dans le dossier textures.
Une fois que l’animation a été comprise avec la durée d’affichage des trames et l’optimisation des images. Nous devons les ajouter au jeu. Modifiez Bob.java
public class Bob {

	// ... omis ... //

	// Garde le temps que l'état a été affiché
	float	stateTime = 0;

	// ... omis ... //

	public void update(float delta) {
		stateTime += delta;		position.mulAdd(velocity.cpy(),delta); 
	}
}
  • Chaque image sera affiché 0.066 seconde.
La classe WorldRenderer.java est celle qui subit le plus de modification.
public class WorldRenderer {

	// ... omis ... //

	private static final float RUNNING_FRAME_DURATION = 0.06f;

	/** Textures **/
	private TextureRegion bobIdleLeft;
	private TextureRegion bobIdleRight;
	private TextureRegion blockTexture;
	private TextureRegion bobFrame;

	/** Animations **/
	private Animation walkLeftAnimation;
	private Animation walkRightAnimation;

	private int walkLeftNbFrames = 5;

	// ... omis ... //

	private void loadTextures() {
		TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("images/textures/textures.atlas"));
		bobIdleLeft = atlas.findRegion("bob", 1);
		bobIdleRight = new TextureRegion(bobIdleLeft);
		bobIdleRight.flip(true, false);
		blockTexture = atlas.findRegion("block");
		TextureRegion[] walkLeftFrames = new TextureRegion[walkLeftNbFrames];
		for (int i = 0; i < walkLeftNbFrames; i++) {
			walkLeftFrames[i] = atlas.findRegion("bob", i + 2);
		}
		walkLeftAnimation = new Animation(RUNNING_FRAME_DURATION, walkLeftFrames);

		TextureRegion[] walkRightFrames = new TextureRegion[walkLeftNbFrames];

		for (int i = 0; i < walkLeftNbFrames; i++) {
			walkRightFrames[i] = new TextureRegion(walkLeftFrames[i]);
			walkRightFrames[i].flip(true, false);
		}
		walkRightAnimation = new Animation(RUNNING_FRAME_DURATION, walkRightFrames);
	}

	private void drawBob() {
		Bob bob = world.getBob();
		bobFrame = bob.isFacingLeft() ? bobIdleLeft : bobIdleRight;
		if(bob.getState().equals(State.WALKING)) {
			bobFrame = bob.isFacingLeft() ? walkLeftAnimation.getKeyFrame(bob.getStateTime(), true) : walkRightAnimation.getKeyFrame(bob.getStateTime(), true);
		}
		spriteBatch.draw(bobFrame, bob.getPosition().x * ppuX, bob.getPosition().y * ppuY, Bob.getSize() * ppuX, Bob.getSize() * ppuY);
	}
	// ... omitted ... //
}
  • On définit le temps alloué pour chaque trame de l’animation.
  • Pour les textures, on définit chacune des textures qui seront utilisées dans le jeu
    • bobIdleLeft et Right représente l’inactivité de Bob dépendant de la direction.
    • blockTexture est l’image pour les blocs.
    • bobFrame est la trame active d’une animation de Bob.
  • La classe Animation est celle qui gère les animations dans libGdx. Celle-ci permet de nous abstraire de toutes les notions de calculs de temps pour chaque trame et le passage d’une trame à l’autre. Dans notre cas, nous définissions une animation pour la gauche et la droite.
  • Dans loadTextures()
    • On charge implémente un TextureAtlas avec le fichier l’atlas de texture qui a été généré par TexturePacker.
    • Pour trouver une texture dans l’atlas, il suffit d’utiliser la méthode findRegion de TextureAtlas. Il y a deux signatures pour findRegion. On peut trouver une image avec son nom en string si elle est unique ou encore on peut utiliser le nom de l’animation complète suivit d’un index de trame.
    • Les textures qui sont dans le paquet sont celles de Bob faisant face à gauche. Pour implémenter les textures pointant à droite, il suffit de flipper l’image de gauche sur l’axe des Y.
    • On déclare un tableau de TextureRegion pour l’animation de marche vers la gauche. On instancie les éléments du tableau dans une boucle qui a le nombre de trame pour l’animation complète.
    • On instancie l’animation avec la durée de chaque trame et le tableau de texture.
  • drawBob est la méthode qui permet de rendre le personnage.
    • La méthode getKeyFrame permet de retourner la trame de l’animation de marche de Bob selon le temps de l’état de Bob.
Cette étape permettra de voir Bob s’animer de gauche à droite, selon l’action envoyée.   Suite et fin ici. Mise à jour par Rémi Rousseau le 18/04/2016

Publié

dans

par

Étiquettes :

Commentaires

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.