Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Jeux à base de tuiles - Initiation à l'isométrie - 2 : Passons au code !

Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par gnicos (Nicolas Gauville), le 03 juillet 2011

Nous allons ici nous intéresser à l'isométrie et à son utilisation dans les jeux à base de tuiles.

Note : Ce tutoriel ne vous apprendra pas à créer un moteur iso ! Ce tutoriel à pour but de montrer comment passer d'un affichage 2D simple (avec des tuiles carrées) à un affichage en isométrie. Le but est de voir l'isométrie de façon indépendante du reste de façon à ne pas restreinte ce tutoriel à un moteur vu auparavant.
Prérequis

Après avoir appris à programmer des jeux à base de tuiles et à dessiner en isométrie, nous allons maintenant rassembler ces deux compétences pour passer d'un moteur 2D à un moteur isométrique.

Attention cependant, nous n'allons pas réaliser un véritable moteur isométrique complet ici, mais seulement voir comment passer de l'affichage 2D à l'affichage iso, pour tout le reste, il n'y a pas de véritable différence entre les deux modes d'affichage, et donc il est inutile d'alourdir ce tutoriel en s'intéressant aux autres points, ceux-ci ayant déjà été vus dans le tutoriel sur les jeux à base de tuiles, ou seront vu dans d'autres tutos “point par point” comme celui-ci.

Nous allons donc voir comment passer d'un programme qui affiche une carte à base de tuiles carrées à un programme final qui affiche des tuiles isométriques. Comme dit dans l'avertissement, nous ne nous intéresserons pas au reste, mais seulement à la vue isométrique.

Pour vous donner une idée, voici globalement ce que donne le passage d'une vue 2D en vue isométrique.

Passons au code : placer les tuiles

Reprenons nos tuiles carrées

Nous allons donc partir d'un programme simple destiné à afficher une carte à l'aide de tuiles carrées. Cette partie sera peu détaillée, tout ceci ayant déjà été vu dans le tutoriel sur les jeux à base de tuiles. Notre programme sera vraiment minimaliste, nous allons juste créer une variable carte (type Array2D), et utiliser deux boucles for imbriquées pour placer correctement les tuiles.

Pour ma part, je vais utiliser les tuiles suivantes :

Pour faire simple, on peu par exemple créer un clip “tile”, dans lequel on place ces six images, en en plaçant une sur chaque frame. Pour faire cela simplement, téléchargez les six images ci-dessus sur votre ordinateur, créer ensuite le clip “tile” et allez à l'intérieur. Une fois fait, utiliser le raccourci clavier “CTRL/CMD + R” pour importer les images, et sélectionnez la première image (t1.png).

Flash devrait alors vous proposer d'importer toutes les images :

Vous n'avez plus qu'à choisir “oui” et flash s'occupera du reste !

Pour pouvoir réutiliser ce clip dans le code, n'oublions pas d'utiliser l'option “Exporter pour ActionScipt, en faisant un clic droit sur le clip dans la bibliothèque et en allant dans “Propriétés”.

Voila, nous pouvons maintenant passer au code. Notre programme étant vraiment très simple, on placera directement le code dans la première image du fichier flash, via l'onglet “Actions - Image”.

Pour commencer, nous allons définir la variable carte, qui, comme indiquée, ne sera ici qu'un simple tableau à deux dimensions (le tableau ci-dessous correspond à l'image de la vue 2D au début de la page, bien sur, n'hésitez pas à remplacer cette carte par une autre de votre choix).

/**
 * On définit la carte.
 */
var map:Array = [[ 6, 6, 6, 6, 5, 6, 6],
		 [ 6, 6, 2, 6, 4, 5, 6],
		 [ 6, 2, 1, 6, 3, 3, 6],
		 [ 6, 1, 1, 6, 6, 6, 6],
		 [ 6, 6, 6, 6, 6, 6, 6]];

On va ensuite créer deux variables qui garderont la taille d'une tuile (ici, 32×32).

/**
 * On définit la hauteur et la largeur d'une tuile.
 */
var tile_width:int = 32;
var tile_height:int = 32;

On enregistre les dimensions de la carte (en nombre de tuiles), de façon à éviter que les conditions des boucles for n'aient à chercher celles-ci à chaque tuile :

/**
 * On enregistre les dimensions de la carte.
 */
var map_width:int = map[0].length;
var map_height:int = map.length;

Nous n'avons maintenant plus qu'à créer la double boucle for pour parcourir la variable map :

/**
 * On utilise deux boucles for pour parcourir toutes les cases de la carte.
 */
for ( var i:int = 0; i < map_width; i++ )
{
	for ( var j:int = 0; j < map_height; j++ )
	{
		/**
		 * On crée la tuile ici.
		 */
	}
}

A l'intérieur des deux boucles for, nous allons maintenant créer et placer notre tuile. Pour commencer, on instantie la classe “Tile” :

/**
 * On instantie la classe "Tile" pour créer une nouvelle tuile.
 */
var tile:Tile = new Tile ();

On utilise ensuite la méthode “gotoAndStop” pour lui donner l'apparence voulue :

/**
 * On lui donne l'apparence correspondant à la valeur de la case de la carte.
 */
tile.gotoAndStop ( map[j][i] );

On la place au bon endroit :

/**
 * On la place au bon endroit.
 */
tile.x = i * tile_width;
tile.y = j * tile_height;

Et on l'ajoute à la liste d'affichage :

/**
 * Et on l'ajoute à la liste d'affichage.
 */
addChild ( tile );

On obtient alors le code suivant :

/**
 * On définit la carte.
 */
var map:Array = [[ 6, 6, 6, 6, 5, 6, 6],
		 [ 6, 6, 2, 6, 4, 5, 6],
		 [ 6, 2, 1, 6, 3, 3, 6],
		 [ 6, 1, 1, 6, 6, 6, 6],
		 [ 6, 6, 6, 6, 6, 6, 6]];
 
/**
 * On définit la hauteur et la largeur d'une tuile.
 */
var tile_width:int = 32;
var tile_height:int = 32;
 
/**
 * On enregistre les dimensions de la carte.
 */
var map_width:int = map[0].length;
var map_height:int = map.length;
 
/**
 * On utilise deux boucles for pour parcourir toutes les cases de la carte.
 */
for ( var i:int = 0; i < map_width; i++ )
{
	for ( var j:int = 0; j < map_height; j++ )
	{
		/**
		 * On instantie la classe "Tile" pour créer une nouvelle tuile.
		 */
		var tile:Tile = new Tile ();
 
		/**
		 * On lui donne l'apparence correspondant à la valeur de la case de la carte.
		 */
		tile.gotoAndStop ( map[j][i] );
 
		/**
		 * On la place au bon endroit.
		 */
		tile.x = i * tile_width;
		tile.y = j * tile_height;
 
		/**
		 * Et on l'ajoute à la liste d'affichage.
		 */
		addChild ( tile );
	}
}

A la compilation, on obtient le résultat suivant (avec la carte vue ici du moins) :

Je vous laisse tout de même le fichier réalisé :

Nous n'avons plus qu'à passer au tuiles isométriques !

Placer les tuiles isométriques, la théorie

Globalement, la grosse différence dans le code va être le placement des tuiles, celles-ci étant, cette fois, des losanges et plus des carrés. Nous allons voir de façon théorique comment calculer leur position en fonction de leurs coordonnées (en nombre de tuiles), étape par étape.

Pour commencer, on va utiliser un debut de map comme base. Les coordonnées sont placées au milieu des tuiles, en rouge et en jaune.

Nous allons commencer par observer leur position (en pixels). Nous pouvons exprimer ces positions en fonction de deux données : la hauteur et la largeur des tuiles (comme c'était fait dans le cas de tuiles carrées).

Notons que nous prenons ici le sommet haut des tuiles comme point d'origine. A vrai dire, le point d'origine n'a pas d'importance, tant qu'il est identique pour chaque tuile.

Ainsi, on observe que la tuile de coordonnées [0,1] a pour position [L/2,H/2], ou la tuile [2,0] a pour position [-2L/2,-2H/2] soit [-L,H].

Pour simplifier, on peut définir deux nouvelles variables A et B, telles que A = L/2 et B = H/2. (le but étant de trouver le lien entre les coordonnées en nombre de tuiles et la position en pixels, nous allons tenter d'avoir l'expression la plus simple possible pour les positions, d'où l'intérêt des variables A et B).

Nous pouvons ici mieux voir le lien entre les coordonnées et les positions :

Ainsi on peu établir une formule qui marchera pour toutes les tuiles et qui va nous permettre de calculer les positions en fonction des coordonnées.

Pour une tuile de coordonnées [I,J], on a donc comme position [( J - I ) * A , (J + I ) * B], comme ceci :

Nous savons donc maintenant comment placer nos tuiles isométriques, nous n'avons donc plus qu'à passer au code !

Et il n'y a plus qu'à modifier le code !

Pour commencer, voici les tuiles isométriques (dans un veritable moteur isométrique, nous n'utiliserions pas ce type de tuiles. Pour les caisses et tonneaux par exemple, on utiliserais des objets séparés que l'on empilerais, mais ici, nous nous contenterons de ça, le but n'étant pas de réaliser un moteur isométrique, mais seulement de voir comment placer les tuiles).

Ces tuiles isométriques sont réalisées à l'aide des tuiles carrées de la première partie, en suivant les techniques vues dans la première page de ce tutoriel (dessiner en isométrie).

Commencez par supprimer le clip “Tile” et les images de tuiles 2D, et recréez le avec ces nouvelles images. Nous pouvons ensuite modifier la carte, les positions des objets sont les mêmes, mais les numéros ont changés ; pour avoir le même rendu, la variable “map” doit maintenant contenir ceci :

/**
 * On définit la carte.
 */
var map:Array = [[ 4, 4, 4, 4, 4, 4, 4],
		 [ 4, 4, 4, 4, 3, 4, 4],
		 [ 4, 4, 4, 4, 3, 3, 4],
		 [ 4, 2, 1, 4, 4, 4, 4],
		 [ 4, 4, 4, 4, 4, 4, 4]];

Nous devons également modifier les variables tile_width et tile_height, les tuiles carrées avaient une dimension de 32×32, les tuiles isométriques ont, elles, une dimension de 64×32. (il s'agit de la dimension d'un sol isométrique de base, les images sont plus grandes car certaines tuiles ont une épaisseur (les caisses et les tonneaux), mais la taille de l'image n'a pas d'importance ici). Nous obtenons donc ceci :

/**
 * On définit la hauteur et la largeur d'une tuile.
 */
var tile_width:int = 64;
var tile_height:int = 32;

Enfin, nous n'avons plus qu'à modifier la façon dont on détermine la position des tuiles, cet à dire modifier ces deux lignes :

/**
 * On la place au bon endroit.
 */
tile.x = i * tile_width;
tile.y = j * tile_height;

En utilisant la formule vue dans la partie précédente, on obtient alors ceci :

/**
 * On la place au bon endroit.
 */
tile.x = ( i - j ) * ( tile_width / 2 );
tile.y = ( i + j ) * ( tile_height / 2 );

A la compilation, on s'aperçoit que les tuiles sont bien placées, mais la carte elle, n'est pas bien placée :

Ici, la carte étant fixe, nous pouvons nous contenter d'ajouter ce que l'on appelle un offset, c'est à dire un décalage fixe appliqué à toutes les tuiles. Pour cela, il suffit de l'ajouter directement dans la formule qui sert à placer les tuiles. Pour une scène de 400 x 225 px, un offset de 200 pixels en X et -50 en Y est suffisant pour replacer la map, on obtient alors ceci :

/**
 * On la place au bon endroit.
 */
tile.x = 200 + ( j - i ) * ( tile_width / 2 );
tile.y = -50 + ( j + i ) * ( tile_height / 2 );

Au niveau du code total, on a alors ceci :

/**
 * On définit la carte.
 */
var map:Array = [[ 4, 4, 4, 4, 4, 4, 4],
				 [ 4, 4, 4, 4, 3, 4, 4],
				 [ 4, 4, 4, 4, 3, 3, 4],
				 [ 4, 2, 1, 4, 4, 4, 4],
				 [ 4, 4, 4, 4, 4, 4, 4]];
 
/**
 * On définit la hauteur et la largeur d'une tuile.
 */
var tile_width:int = 64;
var tile_height:int = 32;
 
/**
 * On enregistre les dimensions de la carte.
 */
var map_width:int = map[0].length;
var map_height:int = map.length;
 
/**
 * On utilise deux boucles for pour parcourir toutes les cases de la carte.
 */
for ( var i:int = 0; i < map_width; i++ )
{
	for ( var j:int = 0; j < map_height; j++ )
	{
		/**
		 * On instantie la classe "Tile" pour créer une nouvelle tuile.
		 */
		var tile:Tile = new Tile ();
 
		/**
		 * On lui donne l'apparence correspondant à la valeur de la case de la carte.
		 */
		tile.gotoAndStop ( map[j][i] );
 
		/**
		 * On la place au bon endroit.
		 */
		tile.x = 200 + ( j - i ) * ( tile_width / 2 );
		tile.y = -50 + ( j + i ) * ( tile_height / 2 );
 
		/**
		 * Et on l'ajoute à la liste d'affichage.
		 */
		addChild ( tile );
	}
}

Et à la compilation, on voit apparaître la magnifique carte isométrique :

Et voici le fichier réalisé :

Conclusion

Vous savez maintenant comment placer des tuiles isométriques ! Bien sur, ces deux pages ne sont qu'une mince introduction à l'isométrie, et il reste encore beaucoup à faire pour obtenir un véritable moteur.

Ce tutoriel n'aborde qu'un seul point technique, et pas un domaine dans son ensemble comme c'était le cas du premier tutoriel sur la réalisation d'un pacman. En effet, ce dernier permet aux débutants de découvrir le principe des jeux à base de tuiles, le fait d'avoir un cour “pas à pas” rend l'apprentissage plus facile, mais force à suivre une certaine façon de coder. Après avoir suivi ce tutoriel, vous aviez déjà les bases pour vous débrouiller dans ce domaine, ainsi, ces autres tutoriels ne sont plus des tutoriels “pas à pas” de façon à vous laisser plus libres dans votre apprentissage.

J'espère que ces pages vous auront plus, et si il y a des questions, pensez à les poser sur le sujet du tutoriel sur le forum.