Journal de bord: création d’un RTS en HTML5, jour 5

Introduction
Ce billet fait suite au billet: http://blog.developpez.com/ducodeetdulibre/p12411/developpement/journal-de-bord-creation-dun-rts-en-html5-jour-4

Dans ce billet, nous verrons la classe Unit, qui permet de gerer des unités

Le constructeur d’unité

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
42
43
44
function Unit(name,src){
    //le nom type d'unité
    this.name=name;
    //l'adresse de l'image
    this.src='img3/'+src;
    this.oImage='';
   
    //les coordonnées + les vies
    this.x=0;
    this.y=0;
    this.life=100;
   
    //la destination cible
    this.targetX='';
    this.targetY='';
   
    //la largeur/hauteur de l'unité
    this.width=widthCase;
    this.height=widthCase;
   
    //contiendra le moment venu un batiment à construire
    this.oBuildOn=null;
   
    //compteur utilisé lors de la récupération de ressource
    this.counter=0;
    //ressources or/bois transporté
    this.or=0;
    this.wood=0;
   
    //pour une ronde point de départ
    this.cycleFromX='';
    this.cycleFromY='';
   
    //pour une ronde point d'arrivée
    this.cycleToX='';
    this.cycleToY='';
   
    //tableau contenant les batiments que l'unité peut construire
    this.tBuildCreation=Array();
   
    if(this.name=='soldat'){
        this.tBuildCreation[0]=new Buildcreation('buid2','build2.png');
    }
}

L’affichage de l’unité
Méthode utilisée pour afficher l’unité
Comme vous pouvez le voir il y a également une partie pour la construction effective d’un batiment.

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
42
43
44
45
46
build:function(){
    //partie affichage de l'image de l'unité sur le canvas
    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_perso.drawImage(this.oImage ,((this.x-currentX)*widthCase),((this.y-currentY)*heightCase),widthCase-2,widthCase-2);
       
        oLayer_perso.fillRect((this.x-currentX)*widthCase,((this.y-currentY)*heightCase)+heightCase-2,widthCase,2,'#00ff00');
       
    }
   
    //si l'unité doit construire un batiment, et qu'elle se trouve sur les lieux de la construction
    if(this.oBuildOn && this.x+1==this.oBuildOn.x && this.y==this.oBuildOn.y){
       
        //création du batiment à l'emplacement
        var aBuild=new Build(this.oBuildOn.name,this.oBuildOn.src);
        aBuild.x=this.oBuildOn.x;
        aBuild.y=this.oBuildOn.y;
        aBuild.build();
       
        //ajout du batiment à la liste des batiments (pour la reconstruction lors des scroll)
        oGame.tBuild.push(aBuild);
        //on sauvegarde les coordonnées du batiments
        oGame.saveBuild(aBuild);
       
        //on reset les propriétés de construction
        oGame.buildcreation='';
        this.buildOnX='';
        this.buildOnY='';
        this.oBuildOn='';
       
        //on décrément la ressource or
        oGame.iOr-=100;
        //on réactualise les ressources
        oGame.buildRessource();
        //on reset la sélection
        oGame.clearSelect();
       
    }
    //on enregistre les nouvelles coordonnées de l'unité
    oGame.saveUnit(this);
},

Quelques remarques, vous pouvez lire certaines portions de code qui seront amenés à être modifié: par exemple le fait que l’on décrémente uniquement l’or de 100 unités et pas le bois lorsque l’on créé un batiment.
Cette notion de cout de construction sera ensuite stoquée dans la classe build afin de permettre d’avoir des batiments de prix différents (or/bois)

Création de la navigation
Lorsque l’on sélectionne une unité, on ne va pas avoir les mêmes possibilités en fonction du type d’unité.
C’est ici qu’intervient la méthode buildNav qui va construire la navigation correspondant à l’unité.

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
buildNav:function(){
    var sHtml='';
   
    if(this.name=='soldat'){
        sHtml='<p><img src="'+this.src+'"></p>';
       
        sHtml+='<h2>Construction</h2>';
       
        var sEnabled='';
       
        //on boucle sur les batiments que l'unité peu construire
        for(var i=0;i&lt;this.tBuildCreation.length;i++){
            if(oGame.iOr &lt; 100){
                 sHtml+=&#039;';
            }else{
                sHtml+='
';
            }
           
            sHtml+='
';
        }
       
    }else{
        sHtml='
<p><img src="'+this.src+'"></p>';
       
    }
   
    getById('
nav').innerHTML=sHtml;
},

Journal de bord: création d’un RTS en HTML5, jour 4

Introduction
Ce billet fait suite au billet: http://blog.developpez.com/ducodeetdulibre/p12406/developpement/journal-de-bord-creation-dun-rts-en-html5-jour-3

Dans ce billet je vais vous détailler le fichier rts_Map.js, son utilisation, sa construction.

Faire une application HTML5/canvas: construire la Map
Dans ce jeux de stratégie, comme dans beaucoup d’autres jeux, la carte est trop grande pour être affichée dans son ensemble,.
Il faut donc afficher une partie de la carte, et permettre de visualiser ce que l’on regarde par rapport à la carte complète.

C’est là qu’intervient la classe Map (fichier rts_Map.js)
Comme pour la classe Game, nous allons ici voir bloc par bloc

Création de la map

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
42
43
44
45
46
47
48
49
50
build:function(){
         
        for(var y=0;y&lt; maxY;y++){
            for(var x=0;x&lt; maxX;x++){
               
                //decalage x/y en fonction du scrolling
                var x2=x+currentX;
                var y2=y+currentY;
                 
                if(this.tMap[y2] &amp;&amp; this.tMap[y2][x2]){
                    //si c&#039;est un arbre
                    if(this.tMap[y2][x2]==4){
                        //on dessine un case normale
                        this.drawImage( 3 ,x,y);
                        //puis on créé un objet arbre par dessus
                        var oWood=new Wood();
                        oWood.x=x;
                        oWood.y=y;
                        oWood.build();
                       
                        //on ajoute cette arbre au tableau des batiments
                        //pour les reconstruire lors du scrolling
                        oGame.tBuild.push(oWood);
                    }
                    //on dessine sur le canvas la valeur du tableau
                    this.drawImage( this.tMap[y2][x2] ,x,y);
                   
                }
            }  
        }
       
    },
    //la methode pour dessiner sur le canvas
    drawImage:function(iImg,x,y){
        if(!this.tOImg[iImg]){
            var oImg=new Image();
            oImg.src=&#039;img3/&#039;+this.tImg[iImg];
            oImg._x=x;
            oImg._y=y;
            oImg.onload=function(){
                oLayer_map.drawImage(this,this._x*widthCase,this._y*heightCase,widthCase,widthCase);
               
            }
            this.tOImg[iImg]=oImg;
           
        }else{
            oLayer_map.drawImage(this.tOImg[iImg],x*widthCase,y*heightCase,widthCase,widthCase);
        }
       
    },

Petite parenthèse sur les images
Pensez bien que lorsque vous souhaitez dessiner une image sur un canvas, vous n’etes pas en local: les images de votre jeu ne sont pas chargées.
Pour gerer ce mode asynchrone: on créé un objet image, on lui assigne des propriétés comme ces coordonnées et enfin on lui indique du code à éxécuter au moment du chargement avec « onload »
Mais il faut également prévoir le fait que l’image ai déjà été chargée précédement.
C’est pour cela que je stoque ici l’objet image dans un tableau de propriété de la classe, ainsi, si l’objet existe on le dessine tout de suite.
En revanche si il n’existe pas on instancie avec les propriétés ainsi que la méthode onload.

Méthode de reconstruction
A chaque scroll, il faut redessiner la map: on se déplace sur la carte, mais il ne faut pas instancier de nouveaux objets arbres
C’est pour cela qu’il y a une méthode rebuild

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rebuild:function(){
    for(var y=0;y&lt; maxY;y++){
        for(var x=0;x&lt; maxX;x++){
           
            var x2=x+currentX;
            var y2=y+currentY;
             
            if(this.tMap[y2] &amp;&amp; this.tMap[y2][x2]){
                if(this.tMap[y2][x2]==4){
                    this.drawImage( 3 ,x,y);
                }
                this.drawImage( this.tMap[y2][x2] ,x,y);
               
            }
        }  
    }
},

La construction de l’aperçu
Il faut également afficher l’aperçu de la carte.
La methode buildApercu permet cela, cette méthode ressemble beaucoup à la méthode build
Les différences sont: on dessine les cases beaucoup plus petites, on dessine sur un calque supérieur un cadre indiquant ce que l’on voit en détail.

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
//construction de l'apercu
    buildApercu:function(){
        var maxMiniY=this.tMap.length;
        var maxMiniX=this.tMap[0].length;
       
        for(var y=0;y&lt; maxMiniY;y++){
            for(var x=0;x&lt; maxMiniX;x++){
               
                var x2=x;
                var y2=y;
               
                if(this.tMap[y2] &amp;&amp; this.tMap[y2][x2]){
                    if(this.tMap[y2][x2]==4){
                        this.drawMiniImage( 3 ,x,y);
                    }
                    this.drawMiniImage( this.tMap[y2][x2] ,x,y);
                }
            }
        }
        oLayer_apercuBrouillard.fillRect(0,0,400,400,&#039;#000000&#039;);
    },
    drawMiniImage:function(iImg,x,y){
        oLayer_apercu.drawImage(this.tOImg[iImg],x*this.miniWidth,y*this.miniWidth,this.miniWidth,this.miniWidth); 
    },
    //dessin du cadre indiquant la partie affichée en détail
    buildApercuCadre:function(){
        oLayer_apercuCadre.clear();
        oLayer_apercuCadre.drawRectStroke(currentX*this.miniWidth,currentY*this.miniWidth,this.miniWidth*maxX,this.miniWidth*maxY,&#039;#ff0000&#039;,2);
    },