Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Exercice 05 - PENDU

Compatible JavaScript. Cliquer pour en savoir plus sur les compatibilités.Par Monsieur Spi, le 17 octobre 2015

Bonjour,

Cinquième exercice de la série, cette fois nous allons nous attaquer au PENDU.
On va un peu faire une pause avec la manipulation de grilles et de tableaux, vous avez du comprendre à ce stade que “les tableaux c'est la vie” pour la plupart des jeux, on va donc aller faire un tour du côté de la manipulation des chaînes de caractères et du texte, et pour cela rien ne vaut une petite chose ludique comme le jeu du pendu.

Avant de commencer, voici à quoi tout ceci va ressembler.

*pour des raisons de sécurité il n'est pas possible de vous présenter le jeu au sein d'une page du wiki, reportez-vous à la source située en bas de cette page pour voir comment ça marche.

Etude préliminaire

Le pendu est un jeu consistant à trouver un mot ou une phrase en devinant quelles sont les lettres qui le composent. Le jeu se joue traditionnellement à deux, avec un papier et un crayon, selon un déroulement bien particulier.

Les deux joueurs dans cet exemple s'appellent A et B.

A pense à un mot et dessine une rangée de tirets, chacun correspondant à une lettre de ce mot.
B annonce une lettre.

  • La lettre fait-elle partie du mot ?
  • Oui : A l'inscrit à sa place autant de fois qu'elle se trouve dans le mot.
  • Non : A dessine le premier trait du pendu.

Le jeu se poursuit jusqu'à ce que :

  • B gagne la partie en trouvant toutes les lettres du mot ou en le devinant correctement.
  • A gagne la partie en complétant le dessin du pendu.

Un jeu vraiment très simple à la fois dans sa version classique et dans sa version informatique. Cependant il va nous permettre d'aborder une notion parfois bien utile, la gestion du texte.

Les pré-requis

Pour ce programme vous devez connaître :

Si vous souhaitez plus de précisions sur ces points, je vous encourage à parcourir le Wiki de Mediabox où vous trouverez de nombreux tutoriaux détaillés.

La structure

Le support principal est une page HTML classique utilisant une simple balise canvas et intégrant une feuille de style et le script du jeu.

<!DOCTYPE html>
<html>
    <head>
        <title>Pendu</title>
	<link rel="stylesheet" type="text/css" href="css/styles.css" />
	<script type="text/javascript" src="js/jeu.js"></script>
	<!--[if lt IE 9]><script type="text/javascript" src="excanvas.compiled.js"></script><![endif]-->
    </head>
    <body>
         <canvas id="canvas">Votre navigateur ne supporte pas HTML5.</canvas>
    </body>
</html>

L'habillage

J'ajoute une bordure à la balise canvas :

canvas {
    border: 1px solid black;
}

Les images

Je prépare tous mes assets, c'est à dire toutes les images prédécoupées qui vont servir à mon jeu.

Je range le tout dans le dossier “assets”, chaque image est nommée “phaseX.jpg” où X correspond au numéro de l'image.

Le code Javascript

Allez c'est parti…

// variables
var canvas, ctx, texte, phrase, erreur, infos, images, touche, lettre, longueur;	
var W = 480;
var H = 480;
 
// préparation du jeu
window.onload = function() {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');
	canvas.width = W;
	canvas.height = H;
	loadImages(5);
}
 
// chargement des images
function loadImages(nbImg){
	images = [];
	for(var i=1; i<nbImg+1; i++){
		var b = new Image();
		b.src = "assets/phase"+i+".jpg";
		b.onload = function() {
			images.push(this);
			if(--nbImg==0) init();
		};
	}
}
 
// initialisation du jeu
function init() {
	erreur = 		0;
	phrase = 		"Vous jouez au pendu sur le Wiki de Mediabox"
	infos = 		phrase.replace(/[A-Za-z]/g,"_");
	longueur = 		phrase.length;
	texte = 		infos;
	render();
	canvas.setAttribute('tabindex','1');
	canvas.focus();
	canvas.addEventListener("keydown", appuie, false);
}
 
// gestion phrase
function appuie(e){	
	touche = (String.fromCharCode(e.keyCode)).toLowerCase();
	lettre = false;	
	for (var i=0; i<longueur; i++)	{
		if (phrase.charAt(i).toLowerCase() == touche){
			infos = infos.substr(0,i)+phrase.substr(i,1)+infos.substr(i+1);
			lettre = true;
		}
	}
	texte = infos;
	if (!lettre) ++erreur;
	render();
	if (erreur>4) finPartie("Perdu, cliquez pour rejouer.");
	for (var j=0; j<longueur; j++)	{
		if (infos.charAt(j) == "_")	return;
	}
	finPartie("Bravo, cliquez pour rejouer.");
}
 
// fin de la partie
function finPartie(message){
	alert(message);
	init();
}
 
// Dessine le jeu
function render() {	
	ctx.fillStyle = "rgb(256,256,256)";
	ctx.fillRect(0, 0, W, H);
	if(erreur>0) ctx.drawImage(images[erreur-1],0,0);
	ctx.fillStyle = "black";
	ctx.font = "16px Arial";
	ctx.textAlign = "center";
	ctx.fillText(infos, W/2, H-30);
}

Etude du programme

// variables
var canvas, ctx, texte, phrase, erreur, infos, images, touche, lettre, longueur;	
var W = 480;
var H = 480;

La listes des variables globales, et deux variables pour la hauteur et la largeur de la zone de jeu (un classique dans nos exercices).

Quand la page est chargée…

// préparation du jeu
window.onload = function() {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');
	canvas.width = W;
	canvas.height = H;
	loadImages(5);
}

On prépare le jeu.
On récupère le canvas et son contexte (la zone de dessin et les outils pour dessiner), on donne une taille au canvas et on charge les images.

// chargement des images
function loadImages(nbImg){
	images = [];
	for(var i=1; i<nbImg+1; i++){
		var b = new Image();
		b.src = "assets/phase"+i+".jpg";
		b.onload = function() {
			images.push(this);
			if(--nbImg==0) init();
		};
	}
}

On se sert tout simplement d'une boucle pour charger une à une toutes les images et les placer dans un tableau.
Notez l'écouteur “onload”, il sert à savoir quand une image à fini d'être chargée, lorsque toutes les images ont été chargées on lance l'initialisation du programme.

// initialisation du jeu
function init() {
	erreur = 		0;
	phrase = 		"Vous jouez au pendu sur le Wiki de Mediabox"
	infos = 		phrase.replace(/[A-Za-z]/g,"_");
	longueur = 		phrase.length;
	texte = 		infos;
	render();
	canvas.setAttribute('tabindex','1');
	canvas.focus();
	canvas.addEventListener("keydown", appuie, false);
}

On met le compteur d'erreurs à zéro, on enregistre la phrase qu'on veut faire découvrir, et fait une copie de cette phrase en replaçant toutes les lettres par des underscores. C'est le premier point intéressant ici, on utilise ce que l'on appelle une REGEX (expression régulière : https://fr.wikipedia.org/wiki/Expression_rationnelle ) pour choisir les lettres à remplacer.

Pour le reste c'est facile, on enregistre la longueur de la phrase, et le texte qu'on va utiliser pour l'affichage, puis on effectue le rendu graphique.

Reste quelques paramètres à ajouter à notre canvas, ce jeu se joue au clavier, il est donc nécessaire de donner le focus au canvas afin que le joueur puisse directement utiliser son clavier et que le jeu réagisse. C'est à ça que va servir “setAttribute('tabindex','1');” (pour en savoir plus : http://www.alsacreations.com/article/lire/570-Histoire-de-tabindex.html ), pour faire simple on va simuler l'appuis par l'utilisateur de la touche TAB au clavier, ce qui a pour but de positionner l'élément à sélectionner dans la page HTML, l'index sert à indiquer quel élément récupérer, ici nous n'avons que le Canvas. Ensuite on donne le focus, c'est à dire la main, au canvas, ainsi le joueur peut directement commencer à jouer avec son clavier, notre canvas à été préalablement sélectionné et on lui a donné le focus. Enfin on termine par un écouteur d'événement, cette fois il n'écoute pas la souris mais le clavier.

// gestion phrase
function appuie(e){	
	touche = (String.fromCharCode(e.keyCode)).toLowerCase();
	lettre = false;	
	for (var i=0; i<longueur; i++)	{
		if (phrase.charAt(i).toLowerCase() == touche){
			infos = infos.substr(0,i)+phrase.substr(i,1)+infos.substr(i+1);
			lettre = true;
		}
	}
	texte = infos;
	if (!lettre) ++erreur;
	render();
	if (erreur>4) finPartie("Perdu, cliquez pour rejouer.");
	for (var j=0; j<longueur; j++)	{
		if (infos.charAt(j) == "_")	return;
	}
	finPartie("Bravo, cliquez pour rejouer.");
}

Quand le joueur appuie sur une touche, on récupére le caractère représenté par cette touche (à l'aide du numéro correspondant) et on le passe en minuscule. Puis on fait une boucle pour parcourir toutes les lettres de la phrase cachée, lorsqu'une lettre correspond à celle choisie par le joueur, on remplace l'underscore correspondant dans la phrase affichée par la lettre en question. Pour celà on va couper tout ce qui se trouve avant la lettre et tout ce qui se trouve après, on change la lettre et on réassemble le tout. Enfin on indique qu'il y avait bien une lettre correcte dans cette phrase.

On met à jour l'affichage et on regarde si il y a eu une erreur (pas de lettre correcte), si le nombre d'erreurs est suppérieur au nombre autorisé la partie est perdue. Sinon, on vérifie si il reste des lettres cachées, si ce n'est pas le cas le joueur gagne la partie.

// fin de la partie
function finPartie(message){
	alert(message);
	init();
}

Si la partie est terminée on affiche une alerte et on relance l'init du jeu pour la prochaine.

// Dessine le jeu
function render() {	
	ctx.fillStyle = "rgb(256,256,256)";
	ctx.fillRect(0, 0, W, H);
	if(erreur>0) ctx.drawImage(images[erreur-1],0,0);
	ctx.fillStyle = "black";
	ctx.font = "16px Arial";
	ctx.textAlign = "center";
	ctx.fillText(infos, W/2, H-30);
}

Et on termine par le rendu graphique, qui se fait au début de partie et à chaque fois que le joueur appuie sur une touche.

On repeind tout l'affichage avec du blanc, notez que cette fois j'utilise une écriture RGB, vous auriez aussi pu utiliser RGBA (couche alpha en plus), ou toute autre forme de notation classique d'une couleur. Si le joueur a déjà fait des erreurs on affiche l'image correspondante à l'erreur en cours, puis on dessine la phrase cachée dans son état actuel et on la positionne.

Conclusion

C'est court et il n'y a pas grand chose à manger là dedans, mais ça devrait vous permettre de commencer à manipuler le texte au sein de vos jeux.

Les sources