Featured image of post Vue.js Monster Slayer

Vue.js Monster Slayer

Une revue de code sur un projet Vue.js

Introduction : le jeu du combat contre le monstre en Javascript

Aujourd’hui je vais commenter le code que j’ai Ă©crit sur un projet de dĂ©couverte des concepts Vue.js. Nous sommes obligĂ©s de passer par lĂ  en tant que dĂ©veloppeur quand nous sommes confrontĂ©s Ă  une nouvelle technologie.

Le but du projet est de crĂ©er un RPG simple. Un systĂšme d’attaque, de soin et de coup spĂ©cial. Une classique.

Cette application est trĂšs minimaliste car c’est un projet pensĂ© pour les personnes n’ayant jamais utilisĂ© de frameworks JavaScript. C’est pourquoi la structure des fichiers ne ressemble pas Ă  un projet Vue.js plus classique. On utilise Ă©galement la librairie via CDN et non via une installation avec Node.js.

Mon but avec cet article est de partager mes acquis en détaillant le code source.

Comment ça fonctionne : décryptage du code source

Cet article est Ă  voir comme un partage de connaissances. Si une faute vous saute aux yeux, je vous invite vivement Ă  me contacter sur LinkedIn.

Connexion entre Vue.js et notre HTML

Afin d’utiliser Vue.js rapidement, nous l’ajouterons au projet via une balise <script>. Pour fonctionner Vue.js doit ĂȘtre montĂ© dans notre fichier HTML principal. Pour faire simple, on lui indique oĂč travailler. GĂ©nĂ©ralement on consacre une balise <div> avec l’identifiant app. Vous ĂȘtes libre sur le choix de l’identifiant. Ici, j’utilise l’identifiant game.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Vue Basics</title>
    <script src="https://unpkg.com/vue@next" defer></script>
    <script src="app.js" defer></script>
  </head>
  <body>
    <div id="game"></div>
  </body>
</html>

Une fois le fichier HTML créé et copiĂ©, vous pouvez l’ouvrir dans votre navigateur favori. Pour l’instant rien ne s’affiche, on peut juste vĂ©rifier que les paquets de Vue.js ont bien Ă©tĂ© tĂ©lĂ©chargĂ©s en allant dans la console du navigateur comme ceci.

La deuxiĂšme Ă©tape pour permettre Ă  Vue.js d’intĂ©ragir avec le DOM se passe cĂŽtĂ© JavaScript. J’ai nommĂ© le fichier app.js, le choix du nom n’est pas important, il suffit juste qu’il corresponse Ă  celui de la balise <script> du fichier HTML. On peut vĂ©rifier, comme avec le fichier de Vue.js, si notre fichier apparaĂźt dans la console.

Viens donc le moment oĂč l’on Ă©crit un peu de JavaScript. Ici, on va initialiser l’application avec l’objet Vue. Pas besoin d’import, l’objet est rendu disponible grĂące au fichier tĂ©lĂ©chargĂ© prĂ©cedemment.

1
2
const app = Vue.createApp({});
app.mount("#game");

Tadaaa, notre script est maintenant prĂȘt Ă  modifier le DOM.

La fonction getRandomValue()

1
2
3
function getRandomValue(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

Cette fonction permet de retourner un nombre aléatoire compris entre la variable min et max. Elle sera utilisée par plusieurs de nos fonctions par la suite.

Math.random() génÚre un nombre aléatoire entre 0 (inclus) et 1 (exclus). Ensuite, on multiplie le nombre généré pour avoir un plus grand interval. Si on multiplie par 3, le nombre généré sera compris entre 0 et 3.

Mais attention, si on utilise que la fonction random(), le nombre gĂ©nĂ©rĂ© sera un nombre dĂ©cimal. Afin d’éviter ce comportement, on utilise la fonction Math.floor() qui permet d’arrondir un nombre Ă  l’entier infĂ©rieur ou Ă©gal.

Les données disponibles

Pour cette application il y a deux types de donnĂ©es. L’un dans la propriĂ©tĂ© data (rĂ©servĂ©e aux donnĂ©es simples) et l’autre dans la propriĂ©tĂ© computed. (rĂ©servĂ©e aux donnĂ©es ayant de la logique)

Données dans data

1
2
3
4
5
6
7
8
9
data() {
    return {
      playerHealth: 100,
      monsterHealth: 100,
      currentRound: 0,
      winner: null,
      logMessages: []
    };
}
  • playerHealth : reprĂ©sente la vie actuelle du joueur.
  • monsterHealth : reprĂ©sente la vie actuelle du monstre.
  • currentRound : numĂ©ro de la manche en cours.
  • winner : nom du vainqueur.
  • logMessages : liste des messages du journal.

Données dans computed

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
computed: {
    monsterHealthStyles() {
      return {
        width: this.monsterHealth <= 0 ? "0%" : this.monsterHealth + "%",
      };
    },
    playerHealthStyles() {
      return {
        width: this.playerHealth <= 0 ? "0%" : this.playerHealth + "%",
      };
    },
    mayUseSpecialAttack() {
      return this.currentRound % 3 !== 0;
    },
}
  • monsterHealthStyles() et playerHealthStyles() : dĂ©termine le style (niveau) de la barre de vie du monstre et du joueur. La propriĂ©tĂ© s’assure que la valeur ne soit jamais infĂ©rieure Ă  zĂ©ro.

  • mayUseSpecialAttack() : dĂ©termine si l’attaque spĂ©ciale du joueur peut ĂȘtre lancĂ©e. Tous les 3 rounds, la condition est vraie, alors l’attaque est rendue disponible.

Les fonctions disponibles

Afin de permettre certaines actions au joueur et au monstre, il faut implémenter des fonctionnalités. La logique et les conséquences de ces actions sont codées dans les fonctions de notre composant Vue.

Les fonctions suivantes se trouvent dans la propriété methods.

1
2
3
4
5
6
7
8
attackMonster() {
  this.currentRound++;

  const attackValue = getRandomValue(5, 12);
  this.monsterHealth -= attackValue;
  this.addLogMessage("player", "attack", attackValue);
  this.attackPlayer();
}

this.currentRound++ permet d’incrĂ©menter le nombre de rounds. Il apparaĂźtra dans chaque action faite par le joueur. On gĂ©nĂšre Ă©galement une valeur alĂ©atoire comprise entre 5 et 12 qui reprĂ©sente la puissance de notre attaque. this.addLogMessage() permet d’ajouter cette action aux logs, puis on lance l’attaque du monstre en appelant this.attackPlayer().

1
2
3
4
5
attackPlayer() {
    const attackValue = getRandomValue(8, 15);
    this.playerHealth -= attackValue;
    this.addLogMessage("monster", "attack", attackValue);
},

Cette fonction a la mĂȘme logique que la prĂ©cĂ©dente sauf qu’on dĂ©cremente la vie du joueur Ă  la place de celle du monstre. Ne vous mĂ©prenez pas, chaque action a des consĂ©quences.

1
2
3
4
5
6
7
8
specialAttack() {
  this.currentRound++;

  const attackValue = getRandomValue(11, 19);
  this.monsterHealth -= attackValue;
  this.addLogMessage("player", "attack", attackValue);
  this.attackPlayer();
},

L’attaque spĂ©ciale est sensiblement identique Ă  l’attaque basique. La diffĂ©rence se fait dans la gĂ©nĂ©ration du nombre alĂ©atoire, allant de 11 Ă  19 au lieu de 8 Ă  15.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
healPlayer() {
  this.currentRound++;
  const healValue = getRandomValue(8, 20);

  if (this.playerHealth + healValue > 100) {
    this.playerHealth = 100;
  } else {
    this.playerHealth += healValue;
  }

  this.addLogMessage("player", "heal", healValue);
  this.attackPlayer();
},

La fonction de guĂ©rison permet de soigner le joueur uniquement. Elle s’assure Ă©galement que la vie du joueur ne dĂ©passe jamais 100. Cette action est Ă©galement enregistrĂ©e dans les logs.

1
2
3
4
5
6
startNewGame() {
  this.playerHealth = this.monsterHealth = 100;
  this.winner = null;
  this.currentRound = 0;
  this.logMessages = [];
},

La fonction startNewGame() réinitialise toutes les données du jeu. Ce sont les données qui se trouve dans la propriété data().

1
2
3
surrender() {
  this.winner = "monster";
},

Il est Ă©galement possible d’abandonner .. mais personne a besoin de ce bouton. 👎

1
2
3
4
5
6
7
addLogMessage(who, what, value) {
  this.logMessages.unshift({
      actionBy: who,
      actionType: what,
      actionValue: value
  });
}

addLogMessage() permet d’ajouter les actions effectuĂ©es dans les logs.

Petite prĂ©cision, unshift() est une mĂ©thode permettant d’ajouter du contenu au dĂ©but d’un tableau.

À quoi ça ressemble ?

Nous sommes arrivés à la partie finale de cet article : la révélation du contenu, la levée des rideaux, le grand reveal.

À la premiĂšre connexion sur l’application, voici ce Ă  quoi ressemble l’écran.

Une interface des plus basiques. En premier, on retrouve les points de vie de notre hĂ©ros et du monstre. Ensuite on a le “bloc d’actions” oĂč se regroupe toutes les actions possibles.

Et enfin en cours de partie, lors de nos premiĂšres actions, l’écran de log du champ de bataille apparaĂźt. Il permet de voir l’historique des actions menĂ©es par le joueur et le monstre. Ainsi que la valeur associĂ©e Ă  chaque action.

Conclusion

C’est dĂ©jĂ  la fin de mon premier article sur mon blog. GrĂące Ă  ce projet on apprend les premiers concepts de Vue.js. On ne rentre pas dans les dĂ©tails du fonctionnement du framework mais ça peut-ĂȘtre un bon premier projet Ă  reproduire pour les dĂ©butants.

On peut imaginer des amĂ©liorations comme la possibilitĂ© de mettre des niveaux d’expĂ©riences, combattre plusieurs ennemis Ă  la suite, acheter de l’équipement pour amĂ©liorer nos statistiques. Je laisse libre court Ă  votre imagination.

Comme dit en introduction, n’hĂ©sitez pas Ă  me contacter sur LinkedIn si vous avez une remarque.

Il me semble Ă©galement important de crĂ©diter la personne qui est Ă  l’origine de ce projet, que j’ai suivi Ă  mes dĂ©buts sur Vue.js (cours de qualitĂ©) :

Et bien sûr le lien du dépÎt GitHub : vuejs-monster-slayer

Généré avec Hugo
ThÚme Stack conçu par Jimmy