Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Etape 8 – Outils

Par monsieur_spi (Monsieur Spi), le 30 juillet 2011

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Utilisez les flèches du clavier pour diriger le personnage et la barre espace pour tirer.

Le jeu n'a pas énormément changé, les modifications apportées concernent surtout la structure.
Dans cet exercice nous allons également aborder les outils pratiques tels que l'éditeur de niveaux.

Je vous laisse une petite démo de l'éditeur dès à présent, vous pouvez jouer avec et même commencer quelques cartes.Mais pour être efficace et charger de nouvelles cartes je vous recommande de passer par la source et de gérer ça offline. N'essayez pas de charger la carte de test depuis l'éditeur online ca ne marchera pas.

Pour plus de détails sur l'utilisation de l'éditeur rendez-vous dans la section concernée.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Introduction

Cette fois nous approchons réellement de la fin du tutorial. Durant plusieurs mois je vous ai proposé de suivre le développement d’un petit jeu de A à Z, je me suis efforcé de travailler le plus simplement possible pour que les débutants puissent suivre et se faire une première expérience. Ce fut long et difficile, autant pour ceux qui apprennent en me lisant que pour moi qui ait essayé de vous proposer une approche simple, mais je pense que cela n’était pas vain et à ouvert quelques portes à tous ceux qui souhaitent un jour savoir par quel bout attaquer la conception d’un petit jeu.

La conception d’un jeu ne s’arrête pas là, c’est même ici qu’elle commence réellement. Nous verrons rapidement à la fin de l’exercice que créer un jeu ça ne fait pas seulement appel à de la technique mais aussi à beaucoup d’imagination et de talent pour concevoir des univers cohérents.

Mais pour le moment nous n’avons pas encore fini notre travail, et ce n’est pas le moment de s’endormir sur nos lauriers, voici la dernière étape du processus technique, à ce stade les choses devraient aller très vite, il faut apporter quelques modifications au moteur, corriger quelques bugs et quelques oublis, puis nous pencher sur quelques outils pratiques comme l’éditeur.

1 - Adaptations du moteur

outils_01.jpg

Nous avons quelques modification à apporter au moteur, non seulement pour corriger une nouvelle fois quelques bugs qui sont passés au travers des mailles du filet, mais aussi pour adapter certaines choses que je n’avais pas prévues d’utiliser de cette manière au départ, rien de bien important je vous rassure mais il faut quand même le faire. Enfin nous allons utiliser la bibliothèque partagée, et donc adapter le programme en ce sens.

Arborescence

outils_02.jpg

Vous avez sous les yeux la structure définitive du programme. Comme d’habitude je vous ai mis quelques points de repères pour que vous vous y retrouviez facilement. En jaune les modifications concernant les portes verrouillées (nous allons y revenir). En orange les modifications concernant les portes de niveaux, en bleu les corrections de bugs et enfin en rouge les ajouts ou grosses corrections. J’ai mis des points d’arrêts dans la source devant chaque modification, pensez à les retirer si vous utilisez le débogueur de Flash.

Note à propos du stockage des données

Pour le moment je me suis contenté de faire des copier/coller des maps, que je construis avec l’éditeur, sur des calques de code du programme. Rien ne vous empêches de faire les choses proprement en utilisant des fichiers TXT ou XML externes pour stocker les données, les charger, les parser, et les utiliser dans le moteur. Ce sont des choses qui sont montrées dans le code de l’éditeur et que je vous laisse explorer par vous-même, ce n’est pas franchement compliqué.

Corriger le stock

Je ne sais pas comment je me suis débrouillé mais il y a une grosse erreur dans la création du stock, les lignes et les colonnes sont inversées ce qui génère bien sur des bugs sur certaines maps.

Editez le calque « Création du level » et corrigez :

// création du stock
function creeStock():void{
	var i:int;											
	var j:int;											
	for (i=0; i<mapH; i++){
		stock.push([]);		
		for (j=0; j<mapW; j++)
			stock[i].push([]);	
		}
	}
}

Isoler les verrous

Tout d’abord nous allons faire une distinction entre « portes de niveau » et « portes verrouillées », les portes verrouillées sont en fait des simples verrous, elles bloquent le passage, alors que les portes de niveau permettent de changer de map. Chaque type de porte doit avoir un calque d’affichage dédié et pour le moment nous utilisions un calque « portes » pour afficher les verrous, ce qui n’est pas logique. On va donc utiliser le calque d’affichage « portes » pour les portes de niveau et un nouveau calque d’affichage « verrous » pour les portes verrouillées. D’autre part les portes de niveaux sont encore reliées au stock et aux tuiles du décor en ce qui concerne l’affichage, il conviendra de les isoler complètement pour les manipuler plus facilement.

Modifiez tous les codes où les verrous sont affichés dans le calque « portes », et toutes les références, il s’agit des calques :

Objets d'affichage

var verrous:MovieClip =	new MovieClip();

Init

dupliquer("refVerrous","initVerrous");
grille.addChild(verrous);
refVerrous = this["refVerrous"+mapEnCours];

Change map

videCalque(verrous);

Fonctions communes

if(ob==4) O = new Verrous();

Items

// clé verte
if (id==1) {
	perso.cleVerte=true;		
	i = refVerrous.length;			
	while (i--){				
		V = refVerrous[i];			
		if(V[5]==1 && (V[4]==1 || V[4]==2)) {
			murs[V[1]][V[0]]=0;		
			V[4]+=2;			
			O = MovieClip(verrous.getChildByName("t_"+V[1]+"_"+V[0]));
			if(O) O.gotoAndStop(V[4]);	
		}
	}
}
 
// clé rouge
if (id==2) {	
	perso.cleRouge=true;		
	i = refVerrous.length;		 
	while (i--){				
		V = refVerrous[i];	
		if(V[5]==2 && (V[4]==1 || V[4]==2)) {	
			murs[V[1]][V[0]]=0;			
			V[4]+=2;			
			O = MovieClip(verrous.getChildByName("t_"+V[1]+"_"+V[0]));
			if(O) O.gotoAndStop(V[4]);
		}
	}
}

Portes verrouillées

// gestion des portes verouillées
function gestionVerrous():void{
	for each (var i in refVerrous){		
		var ob:MovieClip = MovieClip(verrous.getChildByName("t_"+i[1]+"_"+i[0]));
		if (ob) supprimeObjet(i[2],i[3],verrous,ob);	
		else afficheObjet(i[2],i[3],i[0],i[1],i[4],verrous,4);			
	}
}

Pour les portes verrouillées on devrait être ok, elles sont à présent isolées sur leur calque d’affichage.

Isoler les portes

Passons aux portes de niveaux, et pour commencer je vais ajouter une information aux tableaux de références de chaque porte.

// [depart Y, depart X, arrivée X, arrivée Y, direction départ, direction arrivée, map, frame]

Il s’agit simplement de la référence de la tuile à afficher pour cette porte. Puisque je souhaite isoler complètement les portes de niveau il faut les sortir de la map du décor, créer un nouvel objet de référence contenant les tuiles des portes et donc ajouter la valeur de la tuile à afficher en fin de tableau pour savoir quoi afficher.

Comme pour les portes verrouillées, passons rapidement en revue les ajouts et modifications.

Objets d'affichage

var portes:MovieClip =	new MovieClip();

Init

refPortes = this["refPortes"+mapEnCours];

Création du level

Supprimez les références des portes dans la fonction « creeDecor » afin qu’elles n’apparaissent plus dans le stock.

Change map

videCalque(portes);

Fonctions communes

if(ob==5) O = new Portes();

Portes

// gestion des portes 
function gestionPortes():void{
	for each (var i in refPortes){	
		var ob:MovieClip = MovieClip(portes.getChildByName("t_"+i[0]+"_"+i[1]));
		if (ob) supprimeObjet(i[1]*T,i[0]*T,portes,ob);	
		else afficheObjet(i[1]*T,i[0]*T,i[1],i[0],i[7],portes,5);	
	}
}

Dossier « Joueur » calque « Déplacements »

if (changeMap(perso,L,C)) return V;

Petite explication, ici vu que les portes ne sont plus dans le stock on ne peut plus tester le paramètre « porte » sur l’objet, il faudra donc tester la collision autrement, directement depuis la porte.

Dossier « Ennemis » calque « Déplacements »

if (changeMap(ob,L,C))	return [sens,x,y];

Pour les mêmes raisons qu’au dessus il va falloir à présent que les ennemis détectent les portes. Notez que je passe l’objet qui teste la collision comme paramètre de la fonction, que ce soit pour le joueur ou pour les ennemis.

Change map (de nouveau)

function changeMap(ob:Object, L:int,C:int):Boolean{
		for each (var i in refPortes){	
			if(i[0]==L-1 && i[1]==C && ob.sens==i[4]){								if(ob==perso){	
					supprimeMap();		
					mapEnCours = i[6];	
					initMap(i[3]*T+(Gy+1)*i[5],i[2]*T,i[5]);	
					return true;	
				} else {		
					ob.sens*=-1;	
				}
			}
		}
	return false;
}

On vérifie que l’objet qui teste la collision est le perso auquel cas on change de map, sinon l’objet fait demi tour quand il touche la porte.

Enfin il faut modifier légèrement la gestion des collisions latérales du moteur.

if (murs[L][C]) {}

On supprime la condition inutile qui servait à faire changer de sens les objets autre que le perso.

Et les conditions de suppression du tir pour le joueur et les ennemis, retirez :

p = stock[int(y/T)][int(x/T)].porte;

Et voilà, normalement les portes de niveau et les portes verrouillées sont à présent deux choses distinctes ayant leur propre calque d’affichage et étant complètement autonomes.

Détection des pentes

Un bug s’est glissé dans la détection des pentes, il est facile à voir mais il m’avait échappé.
Il se trouve à la ligne suivante dans le calque « Pentes » du dossier « Collisions » :

if ( (stock[L][C+1].slope==1 || stock[L][C-1].slope==-1) && hit(O,L*T)){}

« C+1 » et « C-1 » sortent des limites de la grille dans certaines conditions, comme par exemple lorsque le héros se trouve sur la colonne 0, la colonne -1 n’existe pas dans nos tableaux, résultat l’appel de « stock[L][C-1] » renvoie une erreur et le jeu plante.

Pour palier à ça il suffit de vérifier que la valeur de C est bien comprise dans le tableau :

if (C>0 && C<mapW-1 && (stock[L][C+1].slope==1 || stock[L][C-1].slope==-1) && hit(O,L*T)){}

C’est un peu long comme condition mais ça fonctionne.

Dégâts des ennemis

Lorsqu'un ennemi sort de la zone visible il est effacé mais existe toujours.
Si on tire sur un ennemi qui existe mais n'est pas affiché la fonction “degatsEnnemis()” renvoie une erreur. Cette fonction vérifie à chaque instant qu'un ennemi n'entre pas en collision avec une balle. Pour çà elle se sert de l'ennemi pour lequel on effectue le test “ob” (passé en paramètre de la fonction), et vérifie que aucune balle “t” n'est située à l'intérieur de l'ennemi.

// degats infligés aux ennemis
function degatsEnnemis(ob:MovieClip,X:int,Y:int):Boolean {	
 
	var i:int = tabTirsJoueur.length;	
	var j:int = refEnnemis.length;		
	var t:MovieClip;		
 
	while (i--){					
		t = tabTirsJoueur[i];			
		if (t.x>=ob.x-dT && t.x<=ob.x+dT && t.y>=ob.y-dT && t.y<=ob.y+T){	
			while (j--){				
				if (refEnnemis[j][1]==X && refEnnemis[j][0]==Y){
					mortEnnemi(ob.x,ob.y);	
                        		stock[X]Y]=[];							
					refEnnemis.splice(j,1);					
					tabTirsJoueur.splice(i,1);			
					ennemis.removeChild(ob);		
					balles.removeChild(t);			
					bruit(chanEnnemi, sonMortEnnemi);	
				}
			}
			return true;	
		}
	}
	return false;				
}

Mais la détection de collision pose un problème si “ob” n'est pas affiché.

if (t.x>=ob.x-dT && t.x<=ob.x+dT && t.y>=ob.y-dT && t.y<=ob.y+T) 

Si “ob” est “null” alors le test ne peut pas se faire et la fonction plante.
Il faut donc n'appeler cette fonction que si “ob” existe.
Ce qui nous ramène à l'endroit où on appelle cette fonction, la fonction “gestionEnnemis()”.

Là on peut lire :

O = MovieClip(ennemis.getChildByName("t_"+i[1]+"_"+i[0]));      // l'ennemi dans la grille
if(degatsEnnemis(O,i[1],i[0])) return;	                    // si l'ennemi est touché stoppe la lecture

“O” est l'ennemi affiché. Il faut donc simplement vérifier que “O” renvoie bien quelque chose avant de tester les dégats.

if(O && degatsEnnemis(O,i[1],i[0])) return; // si l'ennemi est affiché et est touché stoppe la lecture

Si “O” n'est pas “null”, on teste la collision et les dégâts.

2 – Sauver et charger

outils_03.jpg

La sauvegarde et le chargement de la partie sont des choses essentielles que nous n’avons pas encore abordées. Vous allez voir que, comme souvent, c’est en fait très simple. Globalement on utilise un SharedObject ( un Cookie si vous préférez ) qui s’enregistre sur l’ordinateur du joueur. C’est pratique et rapide, mais ce n’est pas ce qui est le plus sécurisé car ce Cookie est accessible au joueur et il peut en modifier les informations, pour peu qu’il sache où chercher et quoi modifier, selon la taille de vos maps et le nombre d’objets je lui souhaite bonne chance, mais on ne sais jamais, autant vous prévenir. Vous pouvez bien sur envisager une sauvegarde en ligne via une base de donnée et du PHP, mais ça complique pas mal les choses surtout si vos jeux sont prévus pour fonctionner aussi offline.

Que sauver ?

Nous sommes partis du principe que l’on faisait un jeu d’aventure/plateforme, qui impose donc de sauvegarder l’état des pièces par lesquelles on peut repasser. Les murs peuvent avoir été modifiés, les éléments de décor également, ainsi que tous les objets, piéges et ennemis.

Les jeux de plateforme classiques comportent généralement entre 8 et 20 niveaux, rarement plus, mais ce sont de grand niveaux scrollés et indépendants. Les jeux d’aventure/plateforme peuvent quand à eux comporter jusqu’à 60 niveaux voire plus, souvent de petites pièces d’un château et de longs couloirs ou extérieurs.

Cela commence à faire du monde, et prend de la place, or la limite de poids d’un SharedObject est de 100 Ko seulement. C’est pourquoi la plupart des jeux de ce type sont découpés en zones, on passe des zones composées d’un certain nombre limité de pièces, quand une zone est passée on ne revient pas dans la précédente. Par exemple, zone 1 : jardin, zone 2 : château, zone 3 : catacombes, zone 4 : cimetière, zone 5 : marais, zone 6 : antre du dragon, etc….

Les données de chaque zone sont alors stockées dans un fichier externe (TXT ou XML nous en avons parlé plus haut), on charge un nouveau fichier à chaque changement de zone. On peut aussi fractionner la progression au sein d’une zone, par exemple le joueur passe dans un tunnel et comme par hasard après son passage le tunnel s’effondre, impossible de revenir en arrière, le joueur viens d’entrer dans un nouveau secteur des catacombes. Dans ce cas on ne sauve que le secteur en cours et les différents paramètres généraux comme les objets transportés.

Une autre solution serait de créer un ensemble de scripts dont le but est de modifier les tableaux de base en fonction de certains paramètres, un peu comme on le fait en temps réel quand on ouvre les portes verrouillées dans nos exercices, si le héro possède la clé 1 toutes les portes vertes de tous les niveaux s’ouvrent, etc…, ainsi nous n’avons besoin de sauvegarder que quelques paramètres.

Il existe de nombreuses possibilités pour limiter les données à sauvegarder. Gardez ceci en tête lorsque vous allez créer vos jeux car il faudra alors adapter le programme pour la sauvegarde et le chargement de chaque zone ou chaque secteur en fonction de votre construction. Selon le volume de données à charger et si vous changez de planches de tuiles, apprêtez-vous à devoir créer des « loadings » entre chaque partie voire éventuellement pour chaque sauvegarde.

Sauvegarde

Selon un vieil adage, « qui peut le plus, peut le moins », je vais donc faire quelque chose de très générique dans cet exercice, à vous de l’adapter à votre propre construction par la suite, gardez en tête que c’est le volume de données qui compte, à vous de voir comment le gérer au mieux.

Editez le calque « Variables » et ajoutez :

var saveLocale:SharedObject= SharedObject.getLocal("savePlateformes");

On vérifie si le Cookie nommé « savePlateformes » existe.
Si il n’existe pas il est créé automatiquement.

Editez le calque « Sauvegarde / Chargement » et écrivez :

// Sauvegarde 
function sauveDonnees():void{
 
	var p:int;		
	for (p=1; p<nbrMaps+1; p++) {			
		saveLocale.data["saveDecor"+p] = this["map"+p];
		saveLocale.data["saveMurs"+p] = this["murs"+p];
		saveLocale.data["saveMobiles"+p] = this["refMobiles"+p];	
		saveLocale.data["saveItems"+p] = this["refItems"+p];	
		saveLocale.data["savePortes"+p] = this["refPortes"+p];	
		saveLocale.data["saveVerrous"+p] = this["refVerrous"+p];
		saveLocale.data["saveEnnemis"+p] = this["refEnnemis"+p];	
	}
	saveLocale.data.savePerso = [			
					mapEnCours,
					perso.x,
					perso.y,
					perso.sens,
					perso.cleVerte,
					perso.cleRouge,
					perso.vies,
					perso.sante,
					perso.munitions
					];
	saveLocale.flush();	
}

On enregistre chaque tableau de chaque map dans un nouveau tableau situé dans le Cookie.
On y sauve également un tableau qui regroupe l’état du héro et la map en cours.
Enfin on écrit dans le Cookie avec la méthode « flush() ».

Pour sauver une partie je propose d’utiliser simplement la touche « S » du clavier.
Ainsi le joueur peut sauver à n’importe quel moment.

Editez le calque « Touches » et ajoutez :

if (event.keyCode == 83) sauveDonnees();

Et c’est tout pour la sauvegarde, vraiment pas bien méchant.
Méfiez vous cependant du poids total, là je sauve un peu tout en vrac sans faire le tri mais vous pouvez affiner un peu pour vos besoins. Si vous sauvez de gros volumes de données, mettez le jeu en pause, surveillez ce qu’il se passe et avertissez le joueur qu’il doit attendre un peu. Pensez également à mettre quelques sécurités pour vérifier que tout se déroule comme vous le voulez, il n’y a rien de plus frustrant pour un joueur qu’un système de sauvegarde défaillant.

Chargement

Ce n’est pas plus compliqué que la sauvegarde, il faut juste bien respecter l’ordre dans lequel les choses se font.

Editez le calque « Variables » et ajoutez :

var chargePartie:Boolean = false;

On utilisera une variable pour indiquer qu’un chargement de partie est en cours.

Editez le calque « Sauvegarde / Chargement » et écrivez :

function chargeJeu(e:Event):void{
	if (saveLocale.data.saveDecor1!= undefined) {				
		var p:int;					
		for (p=1; p<nbrMaps+1; p++) {			
			this["map"+p] = 		saveLocale.data["saveDecor"+p];
			this["murs"+p] = 	saveLocale.data["saveMurs"+p];	
			this["refMobiles"+p] = 	saveLocale.data["saveMobiles"+p];
			this["refItems"+p] = 	saveLocale.data["saveItems"+p];	
			this["refPortes"+p] = 	saveLocale.data["savePortes"+p];	
			this["refVerrous"+p] = 	saveLocale.data["saveVerrous"+p];
			this["refEnnemis"+p] = 	saveLocale.data["saveEnnemis"+p];
		}
		chargePartie = true;	
		init(null);	
		perso.x=saveLocale.data.savePerso[1];	
		perso.y=saveLocale.data.savePerso[2];	
		perso.sens=saveLocale.data.savePerso[3];
	}
}

Lorsqu’on charge la partie on regarde si le Cookie est rempli, si il est vide c’est qu’aucune sauvegarde n’existe on ne peut rien charger (avertir le joueur). Dans le cas contraire on va tout simplement aller rechercher tous les tableaux de toutes les maps et les réaffecter aux tableaux de référence.

On indique qu’on est en train de charger une partie puis on lance l’initialisation du jeu.
Enfin on repositionne le perso et on le dirige dans le bon sens.

Lorsque l’on lance l’initialisation de la partie il y a quelques modifications à faire.

Editez le calque « Init » et modifiez :

// dupliquer les maps
if(!chargePartie){		
	dupliquer("map","initMap");	
	dupliquer("refMobiles","initMobiles");	
	dupliquer("refEnnemis","initEnnemis");	
	dupliquer("refPortes","initPortes");
	dupliquer("refItems","initItems");		
	dupliquer("murs","initMurs");	
	dupliquer("refVerrous","initVerrous");	
}
 
perso = new Perso();	
fond = new Fond();	
 
// paramètres du perso
perso.sauter =			0;
perso.gravite =			1;	
perso.sloped = 			false;	
perso.vit = 			4;	
perso.sens = 			1;
perso.monte = 			0;
perso.invulnerable = 		30;		
perso.ech = 			false;	
perso.alpha = 			1;	
 
if(chargePartie){											// on charge pas de partie
	mapEnCours = 		saveLocale.data.savePerso[0];		
	perso.cleVerte =	saveLocale.data.savePerso[4];		
	perso.cleRouge = 	saveLocale.data.savePerso[5];		
	perso.vies = 		saveLocale.data.savePerso[6];	
	perso.sante = 		saveLocale.data.savePerso[7];	
	perso.munitions = 	saveLocale.data.savePerso[8];	
} else {				
	perso.cleVerte = 	0;	
	perso.cleRouge = 	0;
	perso.sante = 		10;
	perso.vies = 		3;	
	perso.munitions = 	10;	
	mapEnCours = 		1;	
}

Si on est en train de charger une partie on ne duplique pas les tableau d’origine puisqu’on viens de les récupérer dans le Cookie. Il en va de même pour les paramètres du perso et la map en cours.

Enfin, le chargement de la partie se fait uniquement depuis le panneau d’accueil sur le bouton « Charger ».

Editez le calque « Menu » et modifiez :

ajouteBouton(menu.charger,chargeJeu);

Il faut indiquer quelque part que le chargement est terminé ce qui permettra de revenir à l’accueil et charger ou de commencer une nouvelle partie ultérieurement.

Editez la fonction « Initmap » et ajoutez à la fin :

chargePartie = false;

Et c’est tout également, vous voyez ce n’est pas la mer à boire ;-)

3 - Bibliothèque partagée

outils_04.jpg

C’est sans doute un des points les plus importants qui concerne aussi bien l’éditeur que le moteur du jeu. Nous en avons parlé au cours de ces exercices, il est parfois très utile d’utiliser des ressources externes, un peu comme nous avons commencé à le faire avec la musique.

Si c’est possible avec la musique ça l’est aussi avec d’autres ressources comme les tableaux de données (TXT ou XML) mais aussi les planches de tuiles (Bitmaps) ou dans notre cas les clips de références des tuiles (SWF ou SWC).

Nous allons donc nous servir d’un fichier SWF à part pour stocker tous les clips de références des tuiles et le partager entre l’éditeur et le moteur. Ainsi les deux programmes utiliserons la même base graphique ce qui va grandement nous simplifier la vie. Lorsque l’on veut modifier une planche de tuiles on ne modifie que le SWF partagé et la modification se répercute directement sur tous les programmes qui utilisent cette ressource externe.

Charger la bibliothèque

En AS2, sur les anciennes versions de Flash, c’était une opération qui demandait quelques manipulations dans l’interface pour créer un lien entre deux fichiers, mais en AS3 c’est un peu différent, on va charger un fichier externe à l’aide d’un objet Loader, et définir le type de contenu que l’on charge, dans notre cas des classes qui définissent les objets.

Editez le calque « Bibliothèque partagée » et écrivez :

// définition des classes d’objets
var Ennemis:Class;				
var Fond:Class;					
var Perso:Class;						
var Items:Class;							
var Tuiles:Class;						
var Verrous:Class;						
var Portes:Class;						
var Plateformes:Class;
 
// Chargement de la bibliothèque
var chargeClasses:Loader = new Loader();			
chargeClasses.contentLoaderInfo.addEventListener(Event.COMPLETE,finChargeClasses);
chargeClasses.load(new URLRequest("biblio.swf"));						
 
// Réafectation des objets
function finChargeClasses(e:Event):void {
	var domain:ApplicationDomain = chargeClasses.contentLoaderInfo.applicationDomain;	
	Ennemis = 		Class(domain.getDefinition("Ennemis")); 
	Fond = 			Class(domain.getDefinition("Fond"));	
	Perso = 		Class(domain.getDefinition("Perso"));	
	Items = 		Class(domain.getDefinition("Items"));	
	Portes = 		Class(domain.getDefinition("Portes"));
	Tuiles = 		Class(domain.getDefinition("Tuiles"));	
	Verrous = 		Class(domain.getDefinition("Verrous"));	
	Plateformes = 		Class(domain.getDefinition("Plateformes"));	
}

On commence par définir des classes, une pour chaque objet. Puis on charge le SWF de la bibliothèque dans un objet Loader. Lorsque l’objet à fini de se charger on associe nos classes à objets chargés.

Quelques extraits de la doc vont m’aider à clarifier un peu ce qu’on cherche à faire.

ApplicationDomain

La classe ApplicationDomain est un conteneur pour les groupes discrets de définitions de classes. Les domaines d'application sont utilisés pour créer des partitions entre les classes qui appartiennent au même domaine de sécurité. Ils autorisent des définitions multiples de la même classe et permettent aux enfants de recycler les définitions des parents.

getDefinition

Extrait une définition publique du domaine d'application spécifié. La définition peut appartenir à une classe, un nom d'espace ou une fonction.

Donc, pour faire simple, on charge le SWF contenant nos objets, tous exportés pour AS avec une définition de classe qui leur correspond. Quand le chargement est terminé on défini un domaine d’application et on extrait la définition de chaque classe d’objet depuis le domaine.

Attention, il y a quelques modifications mineures à apporter au programme, elles concernent les définitions de classe des objets, si on essaye de définir dès le départ par exemple :

var perso:Perso;

Cela ne pourra pas fonctionner car la classe n’est pas encore construite au moment ou le compilateur lis le programme, il faut donc attendre que toutes les classes soient correctement définies avant de créer les objets. On va donc s’imposer de créer des objets génériques en attendant.

Editez le calque « Objets d'affichage » et modifiez :

var perso:MovieClip;
var fond:MovieClip;

Le perso et le fond sont pour le moment défini comme de simples MovieClip.

Editez le calque « Init » et ajoutez :

perso = new Perso();	
fond = new Fond();

Au moment où on lance la partie on crée les objets avec la bonne classe qui cette fois correspond bien à ce que l’on souhaite créer.

Même problème à deux autres endroits.

Editez le calque « Gestion » du dossier « Ennemis » et modifiez :

var e:MovieClip;

Editez le calque « Création du level » et modifiez :

var t:MovieClip;

Nous en avons fini avec les modifications à ce niveau on va donc faire une courte pause et parler justement de la bibliothèque partagée.

Créer la bibliothèque

Créez un nouveau projet AS3, on se moque éperdument de sa taille ou de sa couleur, on ne va utiliser que la Bibliothèque du projet. Sauvez le projet sous le nom « biblio » c’est lui qu’on va charger dans nos programmes.

Ce fichier doit contenir tous les sprites du jeu donc dans notre cas tous les clips de références.

outils_05.jpg

Importez dans la bibliothèque du projet tous les clips utiles ainsi que les bitmaps et clips intermédiaires qui y sont associés.

Assurez-vous que tous les clips sont bien exportés pour AS avec la définition de Classe correcte. Compilez le projet pour obtenir un fichier « biblio.swf ». Et c’est tout. ;-)

Dans la bibliothèque du moteur, supprimez tout ce que vous avez importé dans la « biblio », aussi bien les clips de références que les bitmaps et le reste. A présent nous avons la structure suivante :

« biblio.swf » : contient tous les tuiles et sprites du jeu
« moteur.swf » : contient le moteur et les sprites de l’interface

Notez qu’on pourrait tout à fait placer les sprites de l’interface en dehors du jeu également, il suffirait de les glisser dans la bibilo et de faire quelques modifications au moteur, mais pour le moment ça ira comme ça, si vous avez compris le fonctionnement de la bibliothèque partagée c’est l’essentiel, vous serez libre de l’utiliser au mieux par la suite.

4 – Loading

outils_06.jpg

Dernière chose importante pour vos joueurs, le chargement du jeu et de ses ressources. Jusqu’à présent notre jeu n’était pas très volumineux, 200 Ko au maximum, mais plus le jeu va être grand et posséder des graphismes variés, plus il va être lourd, et peut donc demander un certain temps de chargement. Pour éviter à vos joueurs de se retrouver devant une page vierge le temps que le jeu se charge on va ajouter un « loading » qui indique au joueur où le chargement en est.

Il existe des « loadings » plus ou moins complexes et détaillés qui vont charger chaque ressource l’une après l’autre, graphismes, sons, animations, données, scripts, et l’indiquer au joueur patient. Il existe aussi des « loadings » très simples qui indiquent simplement une progression générale. Le plus simple que je connaisse se trouve complètement en dehors du programme.

Externe

Voilà comment ça fonctionne, je crée simplement un SWF de la taille de mon jeu et qui contient le loading, ce SWF charge le SWF du jeu et on écoute directement le chargement.

Attention, avec Flash les chargements étant asynchrones, c'est-à-dire que l’animation peut se lancer même si elle n’a pas finie de se charger, il convient de mettre des vérifications un peu partout afin de s’assurer que les données sont bien totalement chargées avant de lancer la partie. Je vous laisses gérer cette partie technique qui ne devrait pas trop vous poser de problèmes à ce stade.

Créez un nouveau projet de la taille du jeu et à la même cadence.

Créez un calque de code « Loading » et écrivez :

var jeu:Loader = new Loader();			
var animChargement:MovieClip = new AnimChargement();
addChild(animChargement);
 
function chargementFini(e:Event):void{			
    	addChild(jeu);			
	removeChild(animChargement);	
}
 
function chargementEnCours(e:ProgressEvent):void{	
	animChargement.stat.text = Math.round(e.bytesLoaded/e.bytesTotal*100)+"  %";
}
jeu.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, chargementEnCours);
jeu.contentLoaderInfo.addEventListener(Event.COMPLETE, chargementFini);		
jeu.load(new URLRequest("etape 7_3.swf"));

Allez dites moi que vous avez compris sans que je vous l’expliques ;-)

On a une animation de chargement (légère de préférence) qui contient un champ texte.
On crée un conteneur « jeu » à l’aide d’un objet « Loader ».
On y charge notre SWF qui contient le jeu et on y colle des écouteurs pour savoir quand le chargement est terminé.
Lorsque le chargement est terminé on retire l’anim de chargement et on affiche le jeu.

Internes

Pour les exercices j’ai fait le choix d’aller à l’essentiel sans me préoccuper de certaines choses auxquelles vous allez forcément être confrontées. Par exemple les musiques, il faut prévoir d’écouter leur chargement proprement pour éviter quelles ne se lancent n’importe quand. Vous devez certainement mieux gérer la playlist pour pouvoir choisir quel morceau lancer à un moment précis. Enfin il vous faudra aller fouiller un peu la doc pour vous apercevoir que vous ne pouvez charger des musiques que si elles se trouvent dans le même domaine que le votre, à moins de passer par des dérivations que je vous laisse là aussi chercher.

Il en va de même pour les différents chargements internes, la bibliothèque partagée ne pèse que 80 Ko, c’est assez peu mais elle ne contient pas grand-chose, il conviendra de gérer proprement son chargement afin d’éviter qu’un joueur lance le jeu alors que toutes les tuiles ne sont pas encore chargées. Pensez aussi que vous pouvez utiliser plusieurs bibliothèques, une par zone différente par exemple, avec des sprites différents. En fonction du nombre de tuiles que vous allez utiliser il faudra forcément adapter le moteur en ce qui concerne le stock et les différentes tranches que vous affectez à chaque type d’objet. Il faut bien sur également penser à vos joueurs et ne pas le laisser poireauter dans le vide, il faut leur créer des animations de chargement pour le faire patienter.

Ne vous laissez pas abattre par une limite ou un écueil, il y a toujours une solution si on cherche un peu, et surtout ne perdez jamais de vue que c’est pour vos joueurs que vous faites le jeu. Faites tout pour les contenter, ne les laissez jamais livrés à eux même, vous vous êtes là pour travailler et apprendre mais eux sont là pour jouer et se détendre.

Nous en avons terminé avec notre moteur, mais ce n’est pas encore la fin du tutorial, il reste encore beaucoup de choses à voir.

5 – Editeur

Nous y voilà enfin à cet éditeur dont je vous rebats les oreilles depuis presque le début des exercices. Si vous avez tout suivit jusque là, l’utilité et le caractère indispensable de cet outil devrait vous sembler évident. Sommairement il sert à écrire et structurer les données, en clair il vous permet de dessiner rapidement vos niveaux de manière ludique et détaillée. Il n’est pas nécessaire de créer un éditeur aussi évolué que je l’ai fait pour cet exercice, le tout est de remplir correctement des grilles avec des références, et de sauvegarder ces grille pour les exploiter ultérieurement dans votre jeu.

Vous avez un exemple d’éditeur ultrabasique ici : Générateur de grilles

Sachez cependant que vous allez passer énormément de temps sur l’éditeur, pas simplement à le construire mais surtout à l’utiliser, c’est avec lui que vous allez créer 80% de votre jeu, il me semble donc nécessaire de perdre un peu de temps à créer un outil agréable à utiliser, facile d’accès et le plus détaillé possible pour avoir le moins d’opérations à faire manuellement par la suite.

Si vous avez encore besoin d’être convaincu, il vaut mieux perdre une journée à développer une fonction qui structure vos tableaux pour vous permettre de les exploiter directement dans votre jeu que de devoir effectuer ces modifications à la main pour chaque tableau du jeu, ce qui vous prendra certainement beaucoup plus de temps au final.

Construire un éditeur n’est donc jamais une perte de temps, cependant ce travail ne peut intervenir que lorsque vous saurez exactement tout ce que votre jeu va avoir besoin comme données et la manière dont elles sont structurée, c’est pourquoi nous n’avons pas pu nous pencher dessus avant.

En soit un éditeur n’a rien de vraiment complexe, il reprend le même schéma que votre jeu, c'est-à-dire des grilles et des calques d’affichages, et y ajoute certaines fonctionnalités comme remplir ces grilles avec des références (celles des tuiles). Comme vous êtes des lecteurs assidus et de bon élèves qui ont tout bien suivit jusque là, je ne vais pas vous faire le détail du code, voyez ça comme des travaux pratiques. Je vous laisse la source détaillée que je vous invite à étudier de près et je vais me contenter pour ma part de vous lister les fonctionnalités, ceci servira également de tutorial de prise en main.

Enfin sachez que Flash n’est pas le meilleur logiciel pour créer un éditeur, AIR qui offre plus de possibilités comme d’enregistrer directement dans des fichiers sur votre disque dur et de nombreux outils pratiques prévus pour créer des interfaces. Si je fais le choix de faire mon éditeur avec Flash c’est d’une part pour vous montrer le processus tout en conservant la structure du jeu, mais aussi parce que cela nous imposerai de faire un tutorial complet sur l’utilisation de AIR avant de pouvoir pondre l’éditeur et que vous le compreniez.

Accueil

outils_07.jpg

On commence par l’écran d’accueil de l’éditeur.
J’ai choisi de vous proposer deux options de base, une qui permet de charger une carte et une qui permet de commencer une nouvelle carte vierge. Nous reviendrons un peu plus tard sur le chargement de carte, ce n’est pas une opération complexe mais elle nécessite que vous ayez connaissance du fonctionnement global de l’éditeur pour bien la comprendre.

Lorsque l’on crée une nouvelle carte on indique le nombre de lignes et de colonnes de la carte. Il n’y a potentiellement pas de limites à la taille des cartes, cependant je vous recommande de ne pas dépasser les 1000 lignes par 1000 colonnes, soit 1 million de cases (soit une carte de 32 000*32 000 pixels, ce qui est carrément énorme pour un jeu de ce type).

Cliquer sur le bouton « Valider » aura pour conséquence de générer automatiquement des grilles de références, des tableaux à deux dimensions, et de placer tous les calques d’affichage, ça vous savez le faire à présent puisque nous l’avons fait pour le jeu.

Présentation générale

outils_08.jpg

Cela peut paraître complexe mais rassurez-vous, vous allez voir qu’en fait c’est très simple. Lorsque vous ouvrez l’éditeur sur une carte vierge voici ce que vous avez sous les yeux.

Zone visible du jeu

outils_09.jpg

Nous l’avons définie à 640*480 pixels pour le jeu, c’est donc à cette taille que nous affichons la zone visible dans l’éditeur. Par défaut c’est le premier fond utilisé qui s’affiche mais vous pourrez le changer plus tard.

Vous constaterez également qu’il n’y a aucun repère sur cette zone visible, vous pourrez également en ajouter par la suite. Comme pour le jeu vous devez garder en tête que ce cadre représente la zone visible du niveau et non toute la map. Détail qui a son importance car comme pour le jeu nous allons devoir utiliser un scrolling pour déplacer la map. La construction est exactement la même que pour le jeu à ceci près qu’on ne se réfère plus à la position du héro pour savoir comment déplacer la map, on utilise simplement les flèches de direction. Comme pour le jeu nous avons plusieurs couches d’objets (ou calques) superposés, pour le moment tous les calques sont vides. Les murs et le décor sont des grilles et les objets mobiles sont traités exactement comme pour le jeu c'est-à-dire via des tableaux de références et une fonction qui indique lorsqu’ils doivent être visibles ou non.

Vous avez donc certainement compris que nous allons reprendre une grande partie du moteur du jeu, à ceci près que nous allons supprimer tout ce qui n’est pas utile pour l’éditeur comme les mouvements des objets mobiles (plateformes, ennemis, etc…), les comportements des objets et tuiles spécialisées (le stock), le héro, etc…

Informations pratiques

outils_10.jpg

Rien de plus simple, ce sont les informations utiles lorsque vous construisez votre jeu, ce sont de simples champs textes que l’on rempli en temps utile. Notez simplement que le chiffre représentant la vitesse du scrolling est en rouge, c’est volontaire de ma part pour vous indiquer que cette valeur peut être modifiée à cet endroit. En clair si vous souhaitez modifier la vitesse du scrolling indiquez le ici, attention vous êtes limités à une vitesse de 32, la taille de nos tuiles, au-delà le scrolling va planter.

Techniquement cela se traduit par de simples références mises à jours en temps réel au sein du programme, vous verrez que j’ai créé une petite fonction qui ne sert qu’à ça, la vitesse de référence qui sert au scrolling est récupérée depuis le champ texte prévu à cet effet.

Zones de prévisualisation

outils_11.jpg

A droite et en haut de l’éditeur il y a trois petits carrés vides.
Ce sont les zones de prévisualisation des pièces, elles vous donnent des informations très utiles. Voici ce qu’elles donnent lorsqu’elles sont remplies.

outils_12.jpg

La première pièce à gauche représente la tuile que vous survolez dans la bibliothèque, cette dernière étant assez petite, avoir une preview plus grande de la pièce qu’on souhaite utiliser me semble indispensable. Vous constaterez qu’un numéro se trouve dans le coin supérieur gauche, il s’agit simplement de la référence de la tuile.

La pièce du centre est la pièce en cours d’édition, c'est-à-dire celle que vous avez sélectionnée et qui va servir d’encre pour le dessin que vous voulez tracer. Elle apparaît lorsque vous avez cliqué sur une pièce de la bibliothèque, ont dit que vous l’avez validée. Le numéro est aussi le numéro de référence de la tuile.

La dernière pièce représente la tuile que vous survolez dans la zone visible. C’est très important car cela vous permet de rapidement retrouver une tuile en particulier. Vous noterez que trois chiffres sont présents, le premier (6) représente la ligne où se trouve la pièce, le second (62) est le numéro de référence de la pièce, et le dernier (15) représente la colonne où se trouve la pièce. Ces informations sont de première importance par exemple lorsque vous allez créer des plateformes, vous connaissez ainsi la ligne et la colonne de départ.

Techniquement parlant c’est très simple à gérer au sein du programme. On crée une copie de la bibliothèque en cours (les set de tuiles) pour chaque pièce de preview. Au survol ou à la validation on change simplement la frame à afficher pour chaque pièce. Il en va de même pour les numéros de référence, souvent il s’agit d’indiquer la frame en cours ou la position de la souris par rapport à la grille.

Bibliothèques

outils_13.jpg

Immédiatement sous la zone de prévisualisation des pièces se trouve la bibliothèque de tuiles. Chaque calque bénéficie de sa propre bibliothèque, nous y reviendrons, celle-ci se présente par tranche de 35 carrés contenant chacun une occurrence du set de tuiles en cours. Par exemple pour le décor je vais créer 35 occurrences du clip de référence des tuiles du décor, puis afficher pour chaque clip une frame différente. J’étale ainsi tout le contenu du clip de référence, chaque clip est réactif à la souris, que ce soit au survol (donne les infos de la preview des pièces) ou au clic (valide une pièce). Les numéros affichés sont simplement les numéros de références des frames. Lorsque le nombre de tuiles contenu dans le clip de référence dépasse les 35 il suffit de créer une petit pagination, c'est-à-dire qu’on affiche (recrée) les tuiles par tranche de 35, deux boutons « suivant » et « précédent » permettent de passer à la page suivante.

Techniquement c’est là aussi très simple à créer, 35 occurrences du set de tuiles en cours que l’on rend réactives à la souris.

Outils de la bibliothèque

outils_14.jpg

Une petite barre d’outils se trouve juste au dessous de la bibliothèque.
Elle comprend les deux boutons « précédente » et « suivante » dont nous venons de parler, un clic sur un de ces boutons permet de recréer une nouvelle bibliothèque qui affiche les bonnes frames du set de tuiles en cours, par tranche de 35.

Au centre vous avez le nom du set utilisé par la bibliothèque, par « set » comprenez « clip de référence qui contient toutes les tuiles d’un certain type », ainsi que le numéro de la page en cours.

L’outil « T » permet de masquer ou d’afficher les numéros de frame sur chaque occurrence de la bibliothèque, je travaille souvent sans ces numéros en fait, cela me permet de mieux voir la tuile que j’utilise, je ne me sers de ces numéros que lorsque j’ai un doute sur une pièce.

L’outil « ouvrir dossier » n’est pas encore actif, je pense simplement ajouter la possibilité de charger des sets de tuiles à la volée pendant l’édition, mais ce n’est pas si simple avec Flash, laissons donc cette option de côté pour le moment.

Techniquement là encore rien de bien compliqué, je vous laisse regarder la source.

Calques et outils

outils_15.jpg

Comme pour le jeu nous avons séparé les calques d’affichages, vous avez donc la possibilité avec cet outil de gérer les calques sur lesquels vous allez écrire. Ce sont exactement les mêmes calques que le jeu dans le même ordre, à ceci près que nous avons ajoutés un calque qui n’est normalement pas visible au sein du jeu, celui des murs. Dans le jeu les zones infranchissables ne sont pas visibles, ce n’est qu’une information, mais pour l’éditeur c’est indispensable.

Chaque calque dispose de trois outils et d’un indicateur.
L’œil permet de masquer ou d’afficher le calque.
Le « T » permet d’afficher ou de masquer les numéros de références des tuiles du calque.
Le cadenas permet de verrouiller l’édition d’un calque tout en le laissant affiché.
Et enfin le crayon représente le calque que vous êtes en train d’éditer, ne cherchez pas à l’utiliser comme un outil c’est une simple information pratique, le calque en cours d’édition est le premier de la liste qui n’est ni masqué ni verrouillé.

Lorsque vous changez de calque la bibliothèque correspondante est automatiquement affichée.

Techniquement, chaque calque de l’éditeur est relié à un calque de la zone d’affichage, ce qui permet de l’afficher ou le masquer ou de le verrouiller. Pour chaque calque d’affichage correspond un clip de référence contenant les tuiles de ce calque ou de ce type d’objet, il convient de modifier l’affichage de la bibliothèque en conséquence lorsque vous changez de calque afin d’être sur de toujours éditer le bon calque avec les bonnes tuiles.

Les outils d’édition

outils_16.jpg

C’est la dernière barre d’outils disponible immédiatement avec l’éditeur.
L’œil affiche ou masque tous les calques d’un coup.
Le dossier permet de revenir à l’accueil pour charger une nouvelle map ou en recommencer une.
La grille vide permet d’afficher ou de masquer une grille de repères dans la zone d’affichage.
La grille pleine permet de remplir directement le calque du décor avec une tuile sélectionnée.
La main permet de déplacer la grille d’affichage à l’aide d’un drag & drop.
La gomme permet de gommer les tuiles du calque en cours d’édition.
L’engrenage permet de sauvegarder la map en cours, ce dernier outil demande plus de détails, nous y reviendrons un peu plus tard.

Objets paramétrés

outils_17.jpg

Certains objets comme les portes, les plateformes ou les ennemis, demandent de saisir plusieurs paramètres. J’utilise donc des fenêtres de paramétrages lorsqu’on ajoute un nouvel objet paramétré.

Pour modifier les paramètres d’un objet déjà créé il vous suffit de cliquer dessus, le programme détecte automatiquement l’objet et affiche ses paramètres. L’objet disparaît temporairement de l’affichage pendant son édition.

Techniquement tout se joue au niveau des tableaux de références et à l’aide de la position des objets.

Charger et sauver

Il est important de permettre la sauvegarde, et donc le chargement, de cartes, tout simplement car vous allez souvent revenir dessus pour les corriger ou les terminer, c’est donc une obligation pour l’éditeur. La méthode la plus simple est le chargement de variable depuis un fichier TXT ou XML, Flash ne permettant pas facilement d’écrire directement dans des fichiers externes, ce n’est pas impossible mais pas facile, il vous faudra donc passer par des phases de copier/coller, à vous de développer des modules plus évolués si vous avez le temps.

Pour sauver une carte, passez par le bouton dédié dans l’éditeur, vous tomberez sur ce panneau.

outils_18.jpg

Précisez un numéro pour la map que vous souhaitez sauver.
Ce numéro est automatiquement rempli si vous venez d’une carte que vous avez chargée.

Vous pouvez sauvegarder indépendamment chaque tableau, ou tous les tableaux mis en forme et clairement séparés, ou encore les tableaux dans une version préformatée.

C’est cette dernière option qui va nous intéresser pour l’éditeur, lorsque vous souhaitez sauvegarder une carte il vous faut passer par l’option de préformatage qui va enregistrer quelques informations supplémentaires comme le numéro de la carte par exemple.

outils_19.jpg

Vous constaterez que les informations sont compactées et que les tableaux sont séparés par le signe « & ». C’est sous cette forme que l’éditeur est en mesure de retrouver ses petits. Vous devez copier l’ensemble des données préformatées puis les coller à la main dans un fichier TXT que vous nommez comme vous le souhaitez. Il vous suffit ensuite d’appeler simplement ce fichier par son nom lorsque vous souhaitez charger cette carte dans l’éditeur.

Bac à sable

Pour vous faciliter la prise en main je vais vous guider pour tracer vos premiers décors.

Commencez par créer un map de 30*36 tuiles.
Masquez tous les calques sauf celui du décor.
Dans la bibliothèque du décor cliquez sur le modèle de tuile que vous souhaitez tracer.
Passez votre souris sur la zone de jeu et cliquez pour dessiner.
Utilisez les flèches du clavier pour scroller la map.

Le reste devrait venir intuitivement si je ne me suis pas trop trompé ;-)

6 – Pistes d’optimisations

Il est temps de vous parler que quelques petites optimisations possibles tant sur le moteur que sur l’éditeur. Mon code est loin d’être parfait, j’en ai conscience, mais il fonctionne. Cependant en l’état il pourrait fonctionner encore mieux, notamment au niveau de la gestion des données.

Les données sont actuellement stockées de manière barbare et complexe alors qu’on pourrait très bien les rendre plus compactes et donc plus légères et plus rapides à traiter.

Abandonner les tableaux à multiples dimensions pour les grilles de décor et de murs. De simples listes peuvent suffire à l’aide d’une petite formule de math simple, l’accès est bien plus rapide sur une liste que sur un tableau à multiples dimensions. D’autre part une liste peut être facilement transformée en byteArray, ou « tableau de bits », la plus petite valeur utilisée en informatique et donc la plus rapide à traiter puisque la plus proche de ce qu’utilise nativement l’ordinateur, pas de traitement intermédiaire.

Utiliser des bitWise ( opérateurs binaires ) pour accélérer les calculs semble également une très bonne solution, là encore il s’agit de travailler au niveau des bits donc dans un format proche de celui utilisé nativement par l’ordinateur.

Utiliser un BSP ( partition binaire de l’espace ) et les vecteurs pour accélérer les calculs de collisions, cet algorithme est assez complexe à mettre en place mais permet de réellement alléger le programme en ne calculant que les points utiles au lieu de tester tous les points d’un déplacement.

Oublier les MovieClip et les objets lourds du genre au profit de Sprites et de simples dessins (Bitmaps) qui sont beaucoup plus léger et encore une fois peuvent s’intégrer dans des byteArrays, l’idéal étant de s’affranchir totalement des calques d’affichages et des clips de tuiles pour les remplacer par un dessin à la volée calculé sur la base des calculs du moteur et de quelques textures.

Utiliser les classes et la POO (voir ce tuto de Nathalie ), la programmation orientée objets est sans conteste la meilleure solution pour créer des programmes clairs, propres et optimisés, mais cela demande une certains maîtrise. Retenez qu’il est préférable de créer un programme propre à la timeline qu’un programme mal fichu en POO, utiliser la POO ne vous garantis pas de programmer correctement, c’est simplement une méthode plus adaptée lorsqu’on s’attaque à des programmes lourds et complexes mais ce n’est pas parce qu’un programme est fait en POO qu’il fonctionnera forcément mieux, cela dépend avant tout du développeur qui est derrière.

Optimiser ses algorithmes, souvent on se lance dans l’écriture d’une fonction ou d’un script tête baissée sans vraiment y réfléchir à l’avance, on sait ce qu’on veut faire à cet instant précis et on s’y connait assez pour l’écrire directement. Mais on oublie trop souvent que ces quelques lignes de code écrites vite fait s’intègrent au sein d’un programme plus vaste dont le fonctionnement général est parfois obscur. Il convient donc de revoir l’ensemble de votre programme, même si il fonctionne très bien, afin d’en optimiser le fonctionnement global. Cela passe par une phase où l’on réécrit posément les algorithmes au propre, on s’aperçoit alors rapidement que certaines choses sont déjà utilisées ailleurs, ou peuvent être raccourcis, remplacé par des constantes, ou carrément supprimées, qu’il existe des méthodes plus rapides et plus simples pour obtenir un même résultat que celles que vous avez mises en place dans l’urgence tant que vous aviez l’idée en tête à ce moment là. Notez que pour de nombreux problèmes des solutions existent déjà, des algorithmes tout prêts et optimisés qu’il ne vous reste plus qu’à transcrire.

Créer des choses réutilisables, c’est indispensable si vous souhaitez vous lancer dans la création d’autres jeux, plus vos moteurs/éditeurs seront pensés « globalement » plus ils seront faciles à adapter pour une autre utilisation. Chaque jeu possède ses particularités mais beaucoup utilisent aussi les mêmes bases de travail, il est donc préférable de faire le travail une fois bien et de l’adapter par petites touches que de refaire tout à chaque fois.

IMPORTANT : utiliser un EnterFrame pour un jeu n’est pas une bonne idée ( voir : comparaisons ), c’est simple et rapide mais ce n’est pas fiable, notamment pour deux raisons, les joueurs peuvent tricher en ralentissant l’animation, et le timing de l’animation n’est pas régulier en fonction des machines ce qui entraîne des retraçages visibles et des saccades. Il ne faut pas se baser sur la vitesse d’exécution du projet mais sur le temps passé depuis son ouverture, ainsi on obtient une véritable régularité, on évite les retraçages et il est impossible de ralentir le jeu.

La communication avec une base de données est souvent utilisée pour sauvegarder les highscores ou tout un tas d’autres choses (sans parler pour le moment de jeux multijoueurs), il convient dans ce cas de protéger la communication entre vos SWF et la base de données pour éviter que des petits malins puissent modifier des choses dans la base. Cela vous impose de ne jamais mettre dans vos SWF les accès à la base de donnée, tout simplement parce qu’un SWF est décompilable à l’aide d’outils spécialisés. Un SWF décompilé vous donne accès à tout son code source et donc aux accès à la base de donnée.

7 - Conseils

Nous avons surtout parlé technique tout au long de ces exercices, mais la conception d’un jeu demande bien plus que de la technique, comme toute œuvre ludique, qu’il s’agisse d’un film, d’un livre, d’un dessin animé, d’une voiture ou d’une glace au chocolat, la phase technique ne représente qu’une petite partie du processus, autour se greffent tout un tas de corps de métiers indispensable.

En clair ce n’est pas parce que vous savez programmer un jeu que vous savez faire un jeu. Scénario, graphisme, level design, musiques et bruitages, dynamique générale, gameplay, et qui sait marketing, packaging, distribution, gestion d’équipe, plannings, financement, commercialisation, … bref on ne peut pas être bon partout, surtout lorsqu’on est seul.

Il est donc indispensable de revoir ses ambitions, souvent démesurées, car même si techniquement vous savez le faire, votre jeu risque fort de faire un flop si tout le reste ne suit pas. N’oubliez pas qu’un jeu est fait pour les joueurs qui, eux, ne sont pas des techniciens mais des utilisateurs avec un esprit très critique, et qui souvent vont fermer le jeu au bout du premier niveau si celui-ci pêche sur certains points.

Il faut accrocher le joueur dès le départ si vous voulez qu’il reste jusqu’au bout et c’est loin d’être une tâche facile, on ne s’improvise pas réalisateur ou designeur, ni musicien ou architecte. Vos premiers jeux devront donc être simples, de manière à vous laisser du temps pour travailler les parties qui ne sont pas vos domaines de prédilection.

Il vaut mieux une petite animation très simple mais très bien faite, qu’une grosse animation bâclée. Ce n’est pas forcément le volume qui compte, mais la qualité que vous mettez dans ce que vous proposez.

Scénario

Tous les jeux, quels qu’ils soient, sont dotés d’un scénario, aussi petit soit-il.
Plus ce scénario sera détaillé et bien construit, plus votre jeu sera profond et captivant.
On ne construit donc pas un scénario n’importe comment, il y a quelques règles à suivre.

Les trois actes

Le scénario doit raconter une histoire ayant certes une introduction, un développement et une fin, mais qui doit également respecter la règle des trois actes.

Le premier acte pose le décor et l’intrigue
On présente le monde, on pose le décor, on introduit les personnages, le héro reçoit une mission à accomplir.

Le deuxième acte montre la progression du héro
Le héros progresse jusqu’à accomplir sa mission mais un ressort dramatique lui impose une nouvelle difficulté juste au dernier moment.

Le troisième acte est la résolution
Le héros triomphe de la dernière difficulté, l’histoire se termine sur une conclusion qui apporte les dernières informations utiles.

A quoi sert le scénario pour un jeu vidéo ?
Si pour les jeux de rôle vous voyez l’intérêt, vous-vous demandez sans doute pourquoi un Casse Brique, un Mario Like ou un Donkey Kong aurait besoin d’un scénario. En dehors de la jolie histoire qu’il raconte, un scénario assure un schéma narratif qui permet de justifier ou d’imposer tout un tas de choses, il assure une cohésion dans le récit, et un jeu vidéo, quelque soit sa forme, est un récit. Il sert de référence pour l’ensemble du processus de création et de narration. Plus ce scénario contient de détails et plus vous avez de possibilités d’affiner l’univers dans lequel vous souhaitez plonger vos joueurs et, par là, d’en définir les règles et de le rendre crédible.

Penons un exemple concret avec Donkey Kong, a priori rien de bien complexe, Mario saute au dessus de tonneaux que lance un singe géant. Oui mais pourquoi ? Qui est Mario ? Quel est son but ? Qui est ce singe géant ? Pourquoi il jette des tonneaux sur un pauvre gars qui ne lui a rien fait ? Et puis tient, pourquoi Mario ne pourrait-il pas voler pour mettre directement une beigne au singe ?

Le scénario va apporter toutes ces réponses simplement et poser les limites et les règles de l’univers où se déroule le jeu.(Wikipedia : le scénario )

Acte 1
Donkey Kong (le singe) est l’animal domestique du charpentier Jumpman (Mario). Maltraité par le charpentier, il s'échappe et kidnappe la petite amie de Jumpman. Le joueur prend le contrôle de Jumpman et doit venir au secours de sa bien-aimée.

Acte 2
Le jeu s'ouvre sur la séquence du gorille grimpant une double échelle d'un site en construction, pour en atteindre le sommet. Il y dépose Lady et martèle le sol de ses pieds, provoquant un tremblement du décor et causant des dégradations, les poutrelles se tordent et forment des plans inclinés. Il se déplace alors à sa position finale et lance un ricanement et commence à lancer des tonneaux qui roulent sur des plans inclinés. Jumpman doit les éviter pour atteindre sa bien aimée. À la fin du niveau, une nouvelle cinématique est introduite : Jumpman rejoint Lady et, comme symbole de leur amour, un cœur apparaît, mais Donkey Kong se lève, agrippe la femme et monte à nouveau les échelles, le cœur se brise en deux et le jeu reprend à l’étage suivant.

Acte 3
Lorsque Jumpman atteint enfin le sommet, le gorille s'écrase par terre, Jumpman et Lady sont finalement réunis. Une courte animation fait la transition et le jeu recommence avec un niveau de difficulté supérieur.

Le scénario est certes simple, mais tout est dit en quelques lignes.
On peut en tirer toutes les informations utiles pour la conception du jeu.
Et il respecte bien la règle des trois actes évoqués juste au dessus.

Il faut bien faire la différence entre histoire et scénario, prenons un autre exemple simple avec un Shoot them up. Si ce genre de jeu ne demande pas vraiment une histoire très développée, son scénario est indispensable, par exemple admettons que nous partions sur l’histoire suivante : un mineur de l’espace a perdu son chemin lors d’une attaque, il tente de rejoindre sa base alors en plein conflit. Sans scénario un peu développé difficile d’imaginer la progression des niveaux du jeu, le scénario va donc pouvoir nous donner la structure suivante :

Intro : un groupe de mineurs de l’espace est attaqué, l’un d’entre eux survit
Level 1 : traversée du champ d’astéroïdes
Level 2 : rencontre avec les éclaireurs ennemis
Level 3 : arrivée à l’entrée de la base
Level 4 : traversée des hangars à navette
Level 5 : protéger les réacteurs de la base
Level 6 : faire sortir les survivants
Level 7 : détruire la flotte ennemie

Notez qu’il n’y a rien de bien complexe à ce niveau, mais nous ne sommes pas tous doués pour raconter des histoires et bien sur la complexité de votre scénario va dépendre du jeu que vous allez faire. Si un casse brique ne vous demandera pas énormément de travail, un jeu de rôle en demandera au contraire une quantité considérable. Dans ce genre de cas l’élaboration d’un scénario se complique mais là aussi quelques règles de base peuvent vous sauver la mise et vous permettre de rédiger un récit honorable.

Cahier des charges

Lorsqu’on travaille en équipe ou en entreprise c’est la partie la plus importante, c’est le document de référence qui met tout le monde au diapason.

Normalement un cahier des charges est un document qui énonce les spécifications de base d’un projet et en défini les tenants et les aboutissants. Il est accompagné d’annexes techniques très détaillées à l’attention de chaque secteur de production. C’est généralement un élément contractuel qui lie un client et un prestataire, il est donc impératif que tous les aspects et paramètres soient pris en compte, y compris les parties financières et juridiques, et ce pour cadrer au mieux le projet.

Dans notre cas nous n’allons pas multiplier les documents pour le plaisir, vous êtes sensé travailler seul pour apprendre à faire des petits jeux et non dans une équipe structurée pour concevoir un produit commercial. J’ai donc pris la décision de réunir ici cahier des charges et annexes techniques.

Ce(s) document(s) est votre bible, il doit contenir toutes les informations détaillées sur votre jeu, décrire techniquement et précisément chaque étape, chaque partie, chaque élément, chaque fonctionnalité, chaque détail. Si le scénario assure la cohésion narrative, le cahier des charges est le support technique indispensable à sa réalisation.

Du cahier des charges vont découler tous les aspects de votre production, il va permettre de quantifier, de planifier, de chiffrer, de soulever les défauts, de mettre en évidences et d’anticiper les difficultés, d’établir une gestion de votre temps, de construire des plannings, de répartir les tâches, de trouver des raccourcis et surtout de ne pas vous perdre en cours de route.

Sa rédaction demande à avoir une vue d’ensemble du projet mais également de bonnes notions du travail de chaque secteur qui va intervenir, et qui vont permettre d’élaborer les documents techniques. Il n’existe pas vraiment de schéma type concernant la rédaction d’un cahier des charges, tout dépend de votre secteur d’activité, du produit ou même des personnes auxquelles vous vous adressez. Un jeu vidéo est un programme comme un autre, soyez le plus méthodique possible, couchez tout sur papier et essayez de vous faire un document béton qui ne laisse rien au hasard.

Vous noterez l’importance accordée à une bonne préparation avant de se lancer sur le moindre exercice, c’est fortement conseillé si vous souhaitez mener vos projets à leur terme dans les meilleures conditions, plus tard ce sera indispensable pour communiquer avec vos équipes et mettre tout le monde sur la même longueur d’onde.

Game et Level Designers

Le Game Designer développe la forme, le concept et la jouabilité, en gros il met en place toutes les règles de bases liées au jeu, comme les propriétés des objets, les règles imposées, les lois essentielles, l’impact phycologique du jeu sur le joueur, … Il crée en fait toute la description du jeu et défini ses limites et ses règles.

Le Level Designer s’occupe quand à lui de la réalisation des niveaux du jeu. Il contribue au gameplay en créant et structurant les environnements et les décors tout en essayant de les rendre cohérents et variés. Un niveau n’est pas un simple assemblage de plateformes disposées à l’arraché, il y a une réelle progression, le joueur ne doit pas s’y ennuyer ni s’y retrouver bloqué, il ne doit pas y avoir de bugs ou d’incohérences qui permettent de transgresser les règles imposées.

L’ensemble du jeu et la conception des différents niveaux demande donc beaucoup d’attentions afin de rendre un univers cohérent et agréable pour vos joueurs. Il va sans dire que la jouabilité est essentielle.

Je vous recommande de regarder toutes les vidéos du Joueur du Grenier, ce n’est pas une pub mais un réel document technique très intéressant pour nous, il recense, en tant que joueur ayant une expérience dans la création de jeu, toutes les erreurs des jeux qui ont fait un bide en leur temps. Vous avez donc par l’exemple et en vidéo tout ce qu’il ne faut surtout pas faire quand on crée un jeu. En plus sa prestation est bourrée d’humour donc vous allez passer un bon moment à découvrir ce qu’il ne faut surtout pas faire.

Outils pratiques

Il existe de nombreux petits outils qui vont vous simplifier la vie, n’hésitez pas à les utiliser dès que vous vous sentirez un peu à l’aide avec le processus.

Les bibliothèques et moteurs

Ce sont des ensembles de scripts prêts à l’emploi qui vont vous simplifier énormément les choses puisque vous n’aurez pas à les développer vous-même, il en existe pratiquement pour tout, de la 3D à la physique, en passant par les maths ou la géométrie. Ils ont été écrits pour simplifier le travail des développeurs et leur éviter de devoir tout reconstruire à chaque fois qu’ils vont concevoir un nouveau programme.

Les bibliothèques sont plus des annuaires de scripts où l’on pioche celui qui nous est nécessaire au sein d’un programme pour effectuer une opération précise. (ref : Bibliothèques logiciel )

Les moteurs sont quand à eux des ensembles complexes de scripts capables de gérer simultanément la plupart des fonctionnalités d’un jeu comme les contrôleurs, les graphismes, l’intelligence artificielle, la détection de collision, la physique et bien d’autres choses. De nombreux jeux se basent sur les mêmes moteurs, dont vous avez une liste détaillée ici : liste des moteurs de jeux

Pour la gestion de la 3D en temps réel dans Flash tournez vous vers les librairies 3D comme Away3D, Sandy ou Alternativa.

Enfin pour la gestion de la physique la référence la plus connue est Box2D.

Il existe également des moteurs tout prêts comme Flixel et bien d’autres. Il est inutile de réinventer la roue quand vous avez compris comment elle marche.

La création musicale

Pour le son vous pouvez utiliser SFXR, un générateur de son 16 bits très intéressant, ou Musagi un sampleur, et Audacity, un très bon logiciel de retouche et d’effets. Si vous souhaitez composer des rythmes, des boucles ou des nappes vous pouvez utiliser la version gratuite de l’excellent Rebirth, qui combine deux TB303, une TR 909 et des boites d’effets à gogo. Un Piano Virtuel c’est toujours très utile pour composer de petites mélodies. Et enfin vous trouverez des banques de sons gratuites en grand nombre sur Dog Sounds

Avec ça vous avez toute la gamme d’outils gratuits nécessaire pour tout faire au niveau du son.

Les graphismes et la 3D

Pour l’image, si vous ne possédez pas Photoshop dirigez vous vers The Gimp qui est son pendant gratuit.

Côté graphismes et animation 3D, Blender semble un des softs gratuits les plus complets, si vous pouvez vous procurer en plus une version de Zbrush gratuite vous disposerez d’un modeleur intuitif très puissant.

8 – Conclusion

Voilà on est arrivé au bout, on dispose à présent d’un brouillon acceptable pour commencer à réfléchir à la création de notre jeu, c’est ici que mon travail s’arrête et que le votre commence, et sans exagérer je pense que je me suis réservé la partie la plus facile du processus. La technique ça fait appel à des recettes éprouvées, on trouve souvent la solution à un problème dans des livres, après une rapide recherche sur Internet ou en réfléchissant un peu, mais tout le reste fait appel à votre imagination et à votre talent, et là çà devient beaucoup plus complexe quand on veut que l’ensemble reste cohérent.

Il y encore tellement à dire et à apprendre, nous avons parcourus ensemble une partie du chemin et je vous ai amené jusqu’aux portes du royaume, mais le voyage ne s’arrête pas là, il vous appartient à présent de les franchir et de faire vos premiers pas sur cette nouvelle terre, ce terreau fertile qui va laisser libre recours à votre imagination.

Nous allons nous retrouver une dernière fois pour une toute dernière partie qui clôturera vraiment ce tutorial et dans laquelle nous parlerons des divers autres gameplays possible à partir d’une construction avec des tuiles.

Il me reste à vous souhaiter de bon développement, n’hésitez surtout pas à venir nous montrer vos créations ou à discuter de tout ça avec nous sur le forum dans la salle réservée.

Les sources

Etape 7 – Habillage < page précédente - page suivante > En cours…