Le blog d'Arcade Village

The Island, les fournisseurs

Pour les amateurs de programmation, continuons notre voyage vers The Island.
Pour rappel, une parcelle (classe Plot) est un empilement de blocs. Mais la parcelle peut aussi contenir un fournisseur (Provider en Anglais). Le fournisseur se dessine au dessus de la parcelle et ne peut accéder qu'aux ressources du bloc le plus haut.
Je vous rappelle aussi que vous pouvez voir l'état d'avancement du jeu ici :
The Island

La première chose que vous verrez sans doute est le comportement des créatures. Mais je trouverai le bug et nous reparlerons des créatures plus tard.

Un fournisseur, comme son nom l'indique, fournit des ressources. Les ressources permettent au joueur de se nourrir ou de fabriquer divers objets.
Pourquoi n'ai -je pas retenu, comme dans Minecraft, la paire bloc/ressource ?
Tout simplement parce que le bloc n'est pour moi qu'un support pour les ressources. Sur un bloc de terre, vous pouvez récupérer de la terre, mais il y poussera aussi de l'herbe. Cette herbe pourra être utile à un joueur ou consommée par un herbivore.
J'ai trouvé aussi que le fournisseur permettait plus de souplesse.
Sur un bloc de sable en bord de mer, le joueur pourrait récolter des algues. Mais sur un bloc de sable du désert, des cactus pousseront.
Dans le jeu Minecraft, chaque bloc fournit un matériau. Quand on réalise que ce jeu propose un terrain quasiment infini, on peut croire en la magie.
Dans le cadre de mon jeu en javascript, je pense être limité sur la vitesse d'affichage et la capacité de sauvegarder le terrain de jeu. La séparation Bloc/Fournisseur me permet aussi d'afficher l'écran de jeu en deux parties superposées :
- La première partie contient le terrain proprement dit ( donc les blocs ). Elle est dessinée une seul fois.
- La deuxième partie contient le joueur, les créatures et les fournisseurs. En effet, les fournisseurs se modifient en fonction de la quantité de ressources qu'ils peuvent offrir. C'est un élément important pour le joueur.

Vous pouvez voir un exemple de fournisseur sur l'écran de jeu, il s'agit de ProviderHerb. Il se trouve sur un bloc de terre en général, mais peut tenter de survivre dans les bord de lac.
En fonction de la quantité de brins d'herbes (et donc de nourriture présente pour les herbivores pas exemple), vous verrez que le dessin est différent.
Vous pouvez aussi remarquer qu'un fournisseur peut coloniser les cases adjacentes à celle où il se trouve.
Voyons maintenant la classe Provider qui est l'ancêtre de tous les fournisseurs.

La classe Provider



class Provider
{
    constructor( gaia, p, ftype, rone )
    {
     this.terrain = gaia;
     this.parcelle = p;
     this.ftype = ftype;
     this.rtype = RESSOURCE_RIEN;
     this.rmax = 0;
     this.rone = rone;
     this.ramount = 0;
     this.ramount_ex = -1;
     this.rw = this.rone;
     this.dcout = 0;
    }

    getType()
    {
        return this.ftype;
    }

    getCoutDeplacement()
    {
        return this.dcout;
    }

    onBiomeCreation()
    {

    }
   
    process()
    {
     this.ramount_ex = this.ramount;

     if ( this.rw++ < this.rone ) return;
     this.rw = 0;
     this.grow();
    }

    grow()
    {
    }

    getRessource( rask )
    {
     if ( rask != this.rtype ) return 0; // Nous n'avons pas la ressource demandée
     return Math.trunc(this.ramount);
    }

    decRessource( amount )
    {
        if ( amount > this.ramount )
          {
           return false;
          }
        this.ramount -= amount;
        return true;
    }


    draw( g )
    {
    }
}

Le constructeur indique au fournisseur le terrain (gaia), la parcelle (p) sur lequel il se trouve, le type de fournisseur (ftype) et son délai de croissance (rone)
Vous voyez deux fonctions :
- getRessource( rask ) qui permet de savoir si une ressource est fournie
- decRessource( amount ) qui permet de décroître le nombre de ressources.
Comme vous l'avez subtilement compris (vous êtes subtil, je le sais !), pour simplifier le jeu, chaque fournisseur ne produit qu'une ressource actuellement. C'est un choix car je veux voir mon jeu évoluer au fur et à mesure que je programme.
Enfin, deux fonctions, grow et draw, sont appelées par le moteur du jeu. draw pour la partie dessin et grow pour l'accroissement des ressources.
Je vous parlais tout à l'heure du ProviderHerb, en voici le code.

La classe ProviderHerb



class ProviderHerb extends Provider
{
    constructor(gaia, p)
    {
        super(gaia, p, PROVIDER_HERB, 10);
        this.rtype = RESSOURCE_HERB;
        this.rmax = 20;  
        this.acote = this.parcelle.width / this.rmax;
        this.pcote = 0;
        this.pdecale = 0;
        this.ramount = 1;
        this.brins_x = new Array(this.rmax);
        this.brins_y = new Array(this.rmax);
        this.ibrin = 0;
        for (this.ibrin = 0 ; this.ibrin < this.rmax ; this.ibrin++ )
           {
            this.brins_x[this.ibrin] = Math.trunc(Math.random() * WCASE );
            this.brins_y[this.ibrin] = Math.trunc(Math.random() * HCASE );
           }
    }

    grow()
    {    
     if ( this.ramount == 0 && Math.random() > .6 ) return; // Quand le champs est vide, il est plus difficile de repousser
     this.ramount_ex = this.ramount;
     if ( this.parcelle.getWater() > 10 && this.parcelle.getNutriment() > 10 )
       {
        if ( this.ramount >= this.rmax )
          {
            if ( Math.random() > .7)
              {
               if ( this.parcelle.essaime() ) this.ramount-= 3; // Cela coûte de se développer
              }  
          }
        else
         {
          this.ramount *= 1.20;
          if ( this.ramount > this.rmax)
            this.ramount = this.rmax;
          if ( this.ramount == 0 ) this.ramount = 1;
         }
       }
     else
       {
        if ( this.ramount > 0 ) this.ramount--;
       }  
    }

    onBiomeCreation() // Cette fonction est appelée à la création d'un biome
    {
      this.ramount = Math.round(this.rmax * .80 ); // Nos bestioles doivent avoir à manger
    }

    draw(g)
    {
 
     g.setColor("#80D080");
     for (this.ibrin = 0 ; this.ibrin < Math.trunc(this.ramount) ; this.ibrin++ )
     {
      g.fillRect(this.parcelle.x + this.brins_x[this.ibrin],
        this.parcelle.y+ this.brins_y[this.ibrin],2,3);
     }

   }
}

Je vous laisse étudier le code. Les variables contenant le mot 'brin' permettent d'afficher des brins d'herbe en fonction de la quantité de ressources RESSOURCE_HERB.
La fonction grow augmente ou diminue les ressources en fonction du terrain et, lorsque les ressources sont au maximum ( this.ramount >= this.rmax), demande à la classe Gaia de pouvoir se développer sur une autre case.
Je vous rappelle que vous pouvez voir l'état d'avancement du jeu ici :

The Island

La prochaine fois, nous parlerons des créatures et nous ajouterons le personnage représentant le joueur. Moi, je dois trouver pourquoi les créatures vont dans l'eau....