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

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

Nous avons dans les précédents billets expliqué chaque fichier du projet, nous allons à partir d’aujourd’hui continuer ce rts pour arriver à un jeu fini ;)

Gerer les couts des batiments
Plutot que d’avoir écrit en dur 100 d’or pour les batiments, on va stoquer dans l’objet batiment le cout en or et en bois de chaque batiment

Pour cela on va editer la classe Build, on y ajoute 2 propriétés costOr et costWood
J’en ai profité pour remanier un peu le constructeur: cette fois on ne recoit que le type de batiment et le constructeur fait le reste (adresse de l’image, cout…)

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
//build
function Build(name,src){
    this.name=name;
    this.oImage='';
   
    this.x=0;
    this.y=0;
    this.life=100;
   
    this.width=widthCase*2;
    this.height=widthCase*2;
   
    this.color='#064474';
    this.bVisibility=1;
   
    this.costOr=0;
    this.costWood=0;
   
    if(this.name=='or'){
        this.color='#e8bb08';
        this.bVisibility=0;
        this.shortname='Mine d\'or';
        this.src='img3/mine-or.png';
        this.unitCreation ='';
    }else if(this.name=='QG'){
        this.shortname='Quartier général';
        this.src='img3/build1.png';
       
        this.unitCreation =new Unit('Worker');
    }else if(this.name=='SoldierHouse'){
        this.shortname='Batiment des soldats';
        this.src='img3/build2.png';
       
        this.costOr=100;
        this.costWood=100;
       
        this.unitCreation =new Unit('Soldier');
    }else if(this.name=='ArcherHouse'){
        this.shortname='Batiment des archers';
        this.src='img3/build3.png';
       
        this.costOr=200;
        this.costWood=50;
       
        this.unitCreation =new Unit('Archer');
    }
   
}

J’ai également remanié la classe unit, c’est également le constructeur qui fait tout: image, nom et batiments constructibles.

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){
    this.name=name;
    this.oImage='';
   
    this.x=0;
    this.y=0;
    this.life=100;
   
    this.targetX='';
    this.targetY='';
   
    this.width=widthCase;
    this.height=widthCase;
   
    this.oBuildOn=null;
   
    this.counter=0;
    this.or=0;
    this.wood=0;
   
    this.cycleFromX='';
    this.cycleFromY='';
   
    this.cycleToX='';
    this.cycleToY='';
   
    this.tBuildCreation=new Array();
   
    if(this.name=='Soldier'){
        this.shortname='Soldat';
        this.src='img3/WPface.png';
       
    }else if(this.name=='Archer'){
        this.shortname='Archer';
        this.src='img3/WC.png';
           
    }else if(this.name='Worker'){
        this.shortname='Ouvrier';
        this.src='img3/WK.png';
       
        this.tBuildCreation.push(new Build('SoldierHouse'));
        this.tBuildCreation.push(new Build('ArcherHouse'));
    }
}

Limitation du scroll à la carte
Pour éviter que l’on puisse scroller à l’infini, on va ajouter un garde fou à la classe Game

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
Game.prototype={
    drawDirection:function(){
        oLayer_cadre.clear();
        //left
        oLayer_cadre.drawRect(0,0,10,oLayer_map.height,'#eeaf17','#eeaf17');
        //right
        oLayer_cadre.drawRect(oLayer_map.width-10,0,10,oLayer_map.height,'#eeaf17','#eeaf17');
        //bottom
        oLayer_cadre.drawRect(0,oLayer_map.height-10,100,10,'#eeaf17','#eeaf17');
        oLayer_cadre.drawRect(500,oLayer_map.height-10,300,10,'#eeaf17','#eeaf17');
        //top
        oLayer_cadre.drawRect(0,0,oLayer_map.width,10,'#eeaf17','#eeaf17');
    },
    goLeft:function(){
        if(currentX-1  map.tMap[0].length){
            return ;
        }
       
        currentX+=1;
        this.rebuild();
        oLayer_cadre.drawRect(oLayer_map.width-10,0,10,oLayer_map.height,'#eeaf17','#eeaf17');
    },
    goDown:function(){
        if(currentY+1+maxY > map.tMap.length){
            return ;
        }
       
        currentY+=1;
        this.rebuild();
        oLayer_cadre.drawRect(0,oLayer_map.height-10,100,10,'#eeaf17','#eeaf17');
        oLayer_cadre.drawRect(500,oLayer_map.height-10,300,10,'#eeaf17','#eeaf17');
    },
    goUp:function(){
        if(currentY-1 < 0){
            return ;
        }
       
        currentY-=1;
        this.rebuild();
        oLayer_cadre.drawRect(0,0,oLayer_map.width,10,'#eeaf17','#eeaf17');
    },

Permettre de scroller via la mini map
Sur une carte très grande, on imagine pas devoir scroller à la souris, ce serait trop long
On préfèrerai cliquer directement sur la map
Pour cela, on va dans un premier temps modifier la partie html afin de prendre en compte l’evenement clic gauche et droite sur la carte d’apercu

Puis dans la classe Game, on rajouter une methode clickApercu

1
2
3
4
5
6
7
8
9
10
11
12
13
clickApercu:function(e){
    //recuperation des coordonnées "tableau" x y
    var x=this.getXApercu(e);
    var y=this.getYApercu(e);
   
    currentX=x-(maxX/2);
    currentY=y-(maxY/2);
   
    if(currentX < 0 ){ currentX=0;}
    if(currentY < 0 ){ currentY=0;}
   
    sDirection='refresh';
},

J'ai également ajouté dans la fonction un rafraichissement des batiments dans le cas d'un scroll via l'apercu

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
function run(){  

    //si la souris est sur une zone active de scroll
    if(sDirection=='up'){
        //scroll haut
        oGame.goUp();
    }else if(sDirection=='down'){
        //scroll bas
        oGame.goDown();
    }else if(sDirection=='left'){
        //scroll gauche
        oGame.goLeft();
    }else if(sDirection=='right'){
        //scroll droite
        oGame.goRight();
    }else{
        //si direction refresh, on redessine la map
        if(sDirection=='refresh'){
            oGame.rebuild();
            sDirection='';
        }
       
        //sinon on affiche les zones réactives
        oGame.drawDirection();
       
        //on raffraichit les unités
        oGame.refreshUnit();
    }
   
   
   
    //dans N secondes on appelera de nouveau cette fonction
    setTimeout(run,fps);
}

Permettre de déplacer une unité en cliquant directement sur l’aperçu
Afin de rendre la tache plus simple, on va factoriser le contenu de la méthode clickdroit (de la classe Game)
En créant une méthode goto, il est plus simple ainsi de permettre via un clic droit sur l’aperçu de déplacer 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
goto:function(x,y){
    //recuperation de batiment sur ces coordonnées
    var aBuild=this.getBuild(x,y);

    //si une unité est sélectionnée et que le batiment cliqué est une mine ou du bois
    if(this.selected!='' && aBuild && ( aBuild.name=='or' || aBuild.name=='wood' )){
        //on créé une ronde du bois/or vers le QG
        //pour alimenter les ressources Or/bois
       
        //on indique que la destination de cycle c'est la mine d'or ou l'arbre
        this.selected.cycleToX=x;
        this.selected.cycleToY=y;

        //on indique que la provenance du cycle c'est le QG
        this.selected.cycleFromX=QGx;
        this.selected.cycleFromY=QGy;

        //on donne comme cible de deplacement la mine d'or/l'arbre cliqué
        this.selected.setTarget(x,y);
    }else if(!this.isWalkable(x,y)){
        //si la case n'est pas accessible, il ne se passe rien
   
    }else if(this.selected!=''){
        //si la case est accessible, on y indique à l'unité d'y aller
        this.selected.setTarget(x,y);
    }
},
//appelé lors d'un clic droit sur le canvas (pour un deplacement d'unité)
clickdroit:function(e){
    //recuperation des coordonnées "tableau" x y
    var x=this.getX(e);
    var y=this.getY(e);

    this.goto(x,y);
    return false;

},
clickdroitApercu:function(e){
    //recuperation des coordonnées "tableau" x y
    var x=this.getXApercu(e);
    var y=this.getYApercu(e);
   
    this.goto(x,y);
    return false;
},