Cascade

Game engine experiences
Open source code

Présentation

Cascade est un jeu de réflexion dont le but est de détruire des séries de blocs alignés de la même couleur. Lorsqu’un bloc est détruit l’ensemble des blocs situés au dessus descend pour combler le vide. Lorsqu’une colonne entière est détruite l’ensemble des colonnes suivantes se déplace pour combler le vide. La partie est terminée lorsqu’il ne reste plus de blocs à détruire ou si plus aucun bloc n’a de bloc voisin permettant de créer une série destructible.

C’est assez maigre comme définition mais cela suffit pour nous attaquer à l’exercice, ce type de jeu étant une variante récente du très célèbre Tetris, aucune définition n’existe sur Wikipedia, il est cependant intéressant à étudier car il pose des problèmes de récursivité et d’optimisation.

Le code Javascript

// variables
var canvas, ctx, W, H, posX, posY, T, C, L, i, images, stock, voisins, valeurs, images;
 
// préparation du jeu
window.onload = function() {
    canvas = document.getElementById('canvas');
    ctx = canvas.getContext('2d');
	W = 480;
	H = 480;
	canvas.width = 	W;
	canvas.height = H;
	posX = canvas.offsetLeft;
	posY = canvas.offsetTop;
	T = 32;
	C = W/T;
	loadImages(5);
}
 
// chargement des images
function loadImages(nbImg){	
	images = [];
	for(i=1; i<nbImg+1; i++){
		var b = new Image();
		b.src = "assets/tuile"+i+".png";
		b.onload = function() {
			images.push(this);
			if(--nbImg==0) init();
		};
	}
}
 
// initialisation du jeu
function init() {
	stock = [];
	voisins = [];
	valeurs = [];	
	for (i=0;i<C*C;i++){
		voisins.push([]);
		valeurs.push(parseInt(Math.random()*4+1));
		stock.push({x : parseInt(i%C)*T, y : parseInt(i/C)*T, id : i, width : T, height : T, frame : valeurs[i]});
	}
	render();
	canvas.addEventListener("mousedown", jouer, false);
	canvas.addEventListener("mouseup", checkTile, false);
}
 
// cliquer sur une case
function jouer(e){
	decouvre(parseInt((e.clientX-posX)/T)+parseInt((e.clientY-posY)/T)*C);
}
 
// découvrir les cases de même couleur
function decouvre(n){
	trouveVoisin(n,stock[n].x/T,stock[n].y/T,C-1,valeurs[n]);
	if(voisins[n].length){
		var v = voisins[n];
		for (var h=0; h<v.length; h++){
			if (v[h].frame!=5) {
				v[h].frame=5;
				decouvre(v[h].id);
				valeurs[v[h].id] = 5;
			}
		}
		voisins[n] = [];
		valeurs[n] = 5;
		stock[n].frame = 5;
		render();
	}
}
 
// trouver les cases vides voisines
function trouveVoisin(i,X,Y,L,F){
	if(X>0 && valeurs[i-1]==F) voisins[i].push(stock[i-1]);
	if(X<L && valeurs[i+1]==F) voisins[i].push(stock[i+1]);
	if(Y>0 && valeurs[i-C]==F) voisins[i].push(stock[i-C]);
	if(Y<L && valeurs[i+C]==F) voisins[i].push(stock[i+C]);
} 
 
// vérifier les tuiles
function checkTile(e) {
	var x = C; 
	while(x--) checkColonne(x);
	checkLigne();
	for (var j=0; j<stock.length;j++) stock[j].frame = valeurs[stock[j].id];
	render();
	verifieJeu();
} 
 
// vérifie une colonne
function checkColonne(c){
	var y = 0;
	while(y<C) {
		i = c+y*C;
		if (valeurs[i+C] && valeurs[i] != 5 && valeurs[i+C] == 5) {
			valeurs[i+C]= valeurs[i];
			valeurs[i] = 5;
			checkColonne(c);
		}
		y++;
	}
}
 
// vérifie une ligne
function checkLigne(){
	var x = C; 
	while(x--) checkDecalage(x);
}
 
function checkDecalage(c){
	var t = valeurs.length-C+c
	if(valeurs[t] !=5 && valeurs[t-1] == 5 && t-1>valeurs.length-C-1){
		var y = 0;
		while(y<C) {
			i = c+y*C;
			valeurs[i-1] = valeurs[i];
			valeurs[i] = 5;
			y++;
		}
		checkLigne()
	}
}
 
// vérifie si il reste des combinaisons jouables	
function verifieJeu(){
	var test = true;
	for (var n=0; n<stock.length; n++){
		if(valeurs[n]!=5){
			trouveVoisin(n,stock[n].x/T,stock[n].y/T,C-1,valeurs[n]);
			if(voisins[n].length) test=false;
			voisins[n] = [];
		}
	}
	if (test) finPartie();
}
 
// fin de partie
function finPartie(){
	alert("Fin de partie, cliquez pour rejouer.");
	init();
}
 
// Dessine le jeu
function render() {	
	for(var i=0; i<stock.length; i++){
		ctx.drawImage(images[stock[i].frame-1], stock[i].x, stock[i].y);
	}
}

A retenir

Ce jeu utilise a fond la récursivité, on la retrouve un peu partout y compris en dehors des jeux, par exemple elle est utilisée dans les algorithmes de “flood fill” ( https://fr.wikipedia.org/wiki/Algorithme_de_remplissage_par_diffusion ).

Commentaires

avatar
  S’abonner  
S'abonner
Facebook Google Linked Skype Twitter
© 2019 Cmarzin - Tous droits réservés | SIRET: 483 511 101 00030 | Mentions légales