Introduction
Ce billet fait suite au billet: http://blog.developpez.com/ducodeetdulibre/p12416/developpement/journal-de-bord-creation-dun-rts-en-html5-jour-7
Ajourd’hui nous allons passer aux sprites
L’idée est d’éviter d’avoir une image par éléments, mais 2-3 images qui contiendrait l’ensemble afin d’avoir peu de fichiers à télécharger
On va créer 2 images: une qui contiendra les images 1×1 (map, unités, arbres…) cases et l’autre les images 2×2 (batiment, mine d’or…)
Ensuite on va créer une classe qui permettra dans un premier temps de charger les 2 images, et dans un second temps d’identifier chaque élément du sprite
Création de la classe de gestion de sprites
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | function Images(){ this.tOImg=new Array(); this.tDetail=new Array(); this.counter=0; } Images.prototype={ //methode qui permet de charger une image load:function(src,idImg){ this.tOImg[idImg]=new Image(); this.tOImg[idImg].src=src; this.tOImg[idImg].onload=function(){ oImages.counter++; preload2(); } }, //methode qui permet d'identifier un élément du sprite setDetailOnId:function(id,y,x,width,height,idImg){ this.tDetail[id]=new Array(); this.tDetail[id]['x']=x; this.tDetail[id]['y']=y; this.tDetail[id]['width']=width; this.tDetail[id]['height']=height; this.tDetail[id]['idImg']=idImg; }, //methode qui permet de dessiner un element sur un des canvas drawImageOnLayer:function(id,x,y,width,height,sLayer){ var oCanvasTmp; if(sLayer=='map'){ oCanvasTmp=oLayer_map; }else if(sLayer=='apercu'){ oCanvasTmp=oLayer_apercu; }else if(sLayer=='perso'){ oCanvasTmp=oLayer_perso; }else if(sLayer=='building'){ oCanvasTmp=oLayer_building; } oCanvasTmp.drawImage2(this.tOImg[ this.tDetail[id]['idImg'] ],this.tDetail[id]['x'],this.tDetail[id]['y'],this.tDetail[id]['width'],this.tDetail[id]['height'],x,y,width,height); }, }; |
Chargement des sprites et identification
Il faut ensuite identifier chaque éléments:
On créé un tableau qui représente virtuellement les éléments sur le sprite
En bouclant dessus, on identifie dans la classe Images ceux-ci
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | oImages=new Images(); var tDetailTmp=new Array(); tDetailTmp=[ ['case-beige2','case-water','case-beige','case-wood'], ['unit-worker'], ['unit-soldier'], ['unit-archer'], ]; for(var y=0;y<tDetailTmp.length;y++){ for(var x=0;x<tDetailTmp[y].length;x++){ oImages.setDetailOnId(tDetailTmp[y][x],y*40,x*40,40,40,'1x1'); } } var tDetailTmp=new Array(); tDetailTmp=[ ['build-SoldierHouse','build-SoldierHouse_-2','build-SoldierHouse_-1'], ['build-QG','build-QG_-2','build-QG_-1'], ['build-ArcherHouse','build-ArcherHouse_-2','build-ArcherHouse_-1'], ['build-mineOr'], ]; for(var y=0;y<tDetailTmp.length;y++){ for(var x=0;x<tDetailTmp[y].length;x++){ oImages.setDetailOnId(tDetailTmp[y][x],y*80,x*80,80,80,'2x2'); } } oImages.load('img3/sprite1x1.png','1x1'); oImages.load('img3/sprite2x2.png','2x2'); |
Dessin d’une image issu du sprite
Pour dessiner, il suffit d’appeler l’objet ainsi.
Exemple pour la classe Build: on dessine l’id « this.idImg sur le canvas « building »
1 | oImages.drawImageOnLayer(this.idImg+this.sSprite,(this.x-currentX)*widthCase,(this.y-currentY)*heightCase,widthCase*2,widthCase*2,'building'); |
Animation de construction d’un batiment
Pour feter l’arrivé des sprites j’ai ajouté un cycle de construction pour les batiments:
Dans la classe Game, ajout de la méthode:
1 2 3 4 5 6 7 8 9 | refreshBuild:function(){ for(var i=0;i< this.tBuild.length;i++){ var oBuild= this.tBuild[i]; if(oBuild.level 3){ oGame.refreshBuild(); iRefreshBuild=0; } iRefreshBuild++; |
note: je gère un compteur pour que le batiment ne se construise pas trop vite.
Optimisation du code
En passant au sprite, il a y a eu une autre optimisation de faite: comme on ne charge que 2 images en début de script, avec un mécanimes d’attente de chargement, on n’a plus besoin de se demander/ de coder de méthode onload asynchrone
Avant:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | build:function(){ if(this.oImage==''){ this.oImage=new Image(this); this.oImage.src=this.src; this.oImage._x=this.x; this.oImage._y=this.y; this.oImage.onload=this.drawImage; }else{ oLayer_building.drawImage(this.oImage ,(this.x-currentX)*widthCase,(this.y-currentY)*heightCase,widthCase*2,widthCase*2); } (...) }, drawImage:function(){ oLayer_building.drawImage(this ,(this._x-currentX)*widthCase,(this._y-currentY)*heightCase,widthCase*2,widthCase*2); }, |
Après:
1 2 | build:function(){ oImages.drawImageOnLayer(this.idImg+this.sSprite,(this.x-currentX)*widthCase,(this.y-currentY)*heightCase,widthCase*2,widthCase*2,'building'); |
Plus besoin de gérer deux modes: si l’image n’existe pas , avec gestion asynchrone via onload + si l’image existe
On affiche simplement l’image via l’objet oImages (via les sprites)
Le github
Le projet GitHub : https://github.com/imikado/rtshtml5