Mis à jour le mardi 1 mars 2016
  • Facile

Ce cours est visible gratuitement en ligne.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mise en place du terrain

Connectez-vous ou inscrivez-vous pour bénéficier de toutes les fonctionnalités de ce cours !

Nous allons maintenant mettre en place la première partie de la carte : le terrain.

Cette partie vous permettra de vous rendre compte de l'utilité des tilesets que nous avons mis en place dans la partie précédente, ainsi que de la facilité que ça nous apporte.

Format de stockage des données

Choix d'un langage de représentation des données

Nous allons tout d'abord commencer par nous interroger sur la manière dont nous allons stocker nos cartes, et plus précisément sur la syntaxe que nous allons utiliser.

À première vue, il existe plusieurs solutions que je vais répertorier ici :

Format

Avantages

Inconvénients

XML

  • Possibilité de structurer correctement notre document

  • Facile à interpréter

  • Standard

  • Les données seront difficilement lisibles dans notre cas (c'est à dire une liste de cases à deux dimensions).

  • Syntaxe très lourde, le fichier sera d'autant plus gros

JSON

  • Syntaxe légère

  • Standard

  • Très lisible

  • Facile à interpréter

Texte brut

  • Syntaxe légère

  • Très lisible

  • Il faudra développer notre propre interpréteur

  • Moins facile et moins propre d'intégrer des valeurs supplémentaires

Binaire

  • Très très léger

  • Complètement illisible visuellement

  • Moins facile et moins propre d'intégrer des valeurs supplémentaires

  • JavaScript est prévu pour traiter des chaînes, pas du binaire. Outre les difficultés que cela impliquerait, nous y perdrions les gains en performances

CSV

  • Léger

  • Standard

  • Éditable dans un tableur

  • Interpréteur facile à faire ou à trouver.

  • Moins facile et moins propre d'intégrer des valeurs supplémentaires

Le format que j'ai choisi pour notre RPG est le JSON.

Structure de nos cartes

Dans notre fichier, nous allons devoir stocker pour le moment les éléments suivants (mais il y en aura d'autres à l'avenir) :

  • Terrain présent sur chaque case

  • Tileset qu'on va utiliser

  • Taille de la carte

Pour la taille de la carte, ça va être facile : nos cases seront stockées dans des tableaux, il suffira donc de récupérer la taille des tableaux.

Avant de poursuivre, je vous invite à enregistrer le tileset que nous utiliserons ici (je l'ai pris sur rpg-maker.fr, puis modifié un peu pour l'adapter à nos besoins), qui est le suivant (je l'ai nommé "chemin.png") :

Tileset de chemin

Voici le code de notre première carte (enregistrez-le dans le dossier "maps", avec l'extension ".json". Pour ma part, il se nomme "premiere.json".) :

{
	"tileset" : "chemin.png",
	"terrain" : [
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10,  8,  6,  6,  6,  6,  6,  6],
		[2, 2, 2, 2, 2, 2, 9, 10, 10, 10, 10, 10, 10, 10, 10],
		[2, 2, 2, 2, 2, 2, 9, 10, 12, 14, 14, 14, 14, 14, 14],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2],
		[2, 2, 2, 2, 2, 2, 9, 10, 11,  2,  2,  2,  2,  2,  2]
	]
}

Pour ceux qui sont courageux ou masochistes (comme moi), vous verrez peut-être dès maintenant à quoi ressemblera la carte. Vous pouvez même la modifier. Comme vous pouvez le voir, cette syntaxe nous permet presque d'avoir un aperçu en deux dimensions du code de la carte, ce qui plus facile à manipuler.

Et tu sors ce code d'où ?

J'ai pris le temps de le faire en mode texte (et c'était d'ailleurs un peu pénible ^^ ). Lorsque l'ensemble du tutoriel sera fini, avec tout ce que vous aurez appris, vous devriez être capable de facilement créer un éditeur de cartes pour tout faire visuellement.

Chargement et affichage du terrain

Structure de la classe

Nous pouvons maintenant passer au codage à proprement parler.

Nous allons créer une classe "Map" (mais vous pouvez la nommer "Carte" si vous préférez l'avoir en français, néanmoins le terme de "map" vous sera plus familier si vous avez un peu l'habitude des jeux vidéo). Cette classe aura pour rôle de charger les données de la carte (que nous avons mises en place dans la partie précédente), et d'afficher le terrain sur demande.

Un peu comme pour le tileset, nous aurons donc une méthode "dessinerMap", qui prendra en paramètre un objet context. Cette méthode y dessinera l'ensemble du terrain.
J'y ajouterai également deux getters : getHauteur() et getLargeur().

Programme de test

Ouvrez votre fichier rpg.js et mettez-y le code suivant (et pensez à faire une sauvegarde du code précédent s'il y a quelque chose que vous souhaitez conserver) :

var map = new Map("premiere");

window.onload = function() {
	var canvas = document.getElementById('canvas');
	var ctx = canvas.getContext('2d');
	
	canvas.width  = map.getLargeur() * 32;
	canvas.height = map.getHauteur() * 32;
	
	map.dessinerMap(ctx);
}

Comme vous pouvez le voir, nous modifions automatiquement la taille du canvas pour que l'ensemble de la carte puisse y tenir. Cette méthode n'est pas la meilleure puisqu'elle nous posera des soucis lorsqu'on voudra faire une carte plus grande que l'écran. Nous allons quand même l'utiliser pour le moment, mais nous y reviendrons dans une prochaine partie.

Chargement des données JSON

Maintenant créez notre classe Map dans le fichier qui va bien, et pensez à l'inclure depuis le fichier HTML.

Notre constructeur chargera les données de la carte, et interprétera le code JSON.
Nous allons donc utiliser AJAX (ou XMLHttpRequest pour les intimes :-° ). Pour nous simplifier la vie, je vais réutiliser la fonction que Thunderseb a mis a disposition dans son tuto sur Ajax. Enregistrez la dans le dossier js (et pensez bien à l'inclure dans votre page HTML).
Nous allons donc commencer par créer une instance de cet objet :

function Map(nom) {
	
	// Création de l'objet XmlHttpRequest
	var xhr = getXMLHttpRequest();

	// Ici viendra le code que je vous présente ci-dessous
}

Ensuite, nous lui demandons de charger le contenu du fichier JSON :

// Chargement du fichier
xhr.open("GET", './maps/' + nom + '.json', false);
xhr.send(null);
if(xhr.readyState != 4 || (xhr.status != 200 && xhr.status != 0)) // Code == 0 en local
	throw new Error("Impossible de charger la carte nommée \"" + nom + "\" (code HTTP : " + xhr.status + ").");
var mapJsonData = xhr.responseText;

Vous noterez que l'objet ne renvoie pas un code HTTP 200 si vous êtes en local puisque vous n'utilisez pas HTTP dans ce cas là.

Nous avons maintenant le contenu de notre fichier (donc le code JSON) dans la variable mapJsonData. Il nous suffit de le "parser", c'est à dire de le transformer en objet(s) JavaScript. Pour cela il existe plusieurs méthodes. La plus propre, c'est d'utiliser la méthode JSON.parse. Mais sur certains navigateurs un peu anciens, cette méthode n'existe pas forcément. Pour eux, il va falloir inclure la librairie JavaScript qui convient (disponible sur le site http://www.json.org/, ou si vous préférez le lien direct vers le fichier, qu'il faudra inclure dans votre HTML, de préférence en premier) :

// Analyse des données
var mapData = JSON.parse(mapJsonData);

JSON étant un langage de représentation tiré de JavaScript, c'est très performant car totalement natif.
Nous avons donc maintenant une variable mapData, qui fait référence à un objet contenant :

  • Un attribut tileset, qui contient le nom du tileset à utiliser

  • Un attribut terrain, qui contient une matrice (ou tableau a deux dimensions) contenant des entiers. Chaque entier est le numéro du tile a utiliser pour la case a laquelle il correspond.

Nous pouvons maintenant charger le tileset requis et stocker la matrice du terrain dans un attribut de notre objet :

this.tileset = new Tileset(mapData.tileset);
this.terrain = mapData.terrain;

Mise en place des méthodes de l'objet

Viennent ensuite nos trois méthodes. Les deux getters sont les plus simples :

// Pour récupérer la taille (en tiles) de la carte
Map.prototype.getHauteur = function() {
	return this.terrain.length;
}
Map.prototype.getLargeur = function() {
	return this.terrain[0].length;
}

La hauteur est définie par le nombre de tableaux (donc de lignes) présents dans le tableau principal.
La largeur est égale à la taille de n'importe quelle ligne (ici j'ai choisi la première puisqu'on a forcément au moins une ligne).

La méthode dessinerMap suivra l'algorithme suivant :

  • On parcourt toutes les lignes

  • Pour chaque ligne, on parcourt toutes les cellules

  • Ensuite on demande au tileset de dessiner le tile dont le numéro est disponible dans la cellule, en lui passant les coordonnées correspondantes, c'est à dire (X = indice de la colonne * 32, Y = indice de la ligne * 32).

Map.prototype.dessinerMap = function(context) {
	for(var i = 0, l = this.terrain.length ; i < l ; i++) {
		var ligne = this.terrain[i];
		var y = i * 32;
		for(var j = 0, k = ligne.length ; j < k ; j++) {
			this.tileset.dessinerTile(ligne[j], context, j * 32, y);
		}
	}
}

Si tout va bien, vous devriez maintenant voir ceci :

Terrain

Nous sommes maintenant capables d'afficher aisément un terrain. Bien sûr c'est un peu vide, mais patience, nous y ajouterons des choses.

Et voilà, nous avons terminé la première partie de notre mini-RPG.

Dans la prochaine partie nous mettrons plus de choses sur notre terrain.

Exemple de certificat de réussite
Exemple de certificat de réussite