Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

TP2e année8 livrablesQuiz corrigé

Le Générateur d'équipe

Un design tiré au hasard qui déclenche des stats, puis un export JSON réutilisable ailleurs.

Par Josselyn C., prof de BTS SIO. Publié le , mis à jour le .

On code
objets · fonctions fléchées · Math.random · le design qui calcule les stats · tableaux · map/forEach/reduce · JSON
Le résultat
on génère une équipe de monstres animés (couleur, yeux, cornes, crocs + PV/attaque), puis on l'exporte en JSON
Outils
navigateur + VS Code, zéro installation · Durée : la journée (~5 h)
Pour qui
SLAM, 2e année
Durée
environ 3 h
Prérequis
Les bases de JavaScript ; idéalement après le TP Fabrique à monstres.
Matériel
Un navigateur (Chrome ou Firefox), VS Code et le projet de départ fourni (index.html, styles.css, sprites.js).

À télécharger : Generateur-equipe-projet-eleve.zip (le projet de départ)

Compétences : C2.1 Concevoir et développer une solution applicative, C2.3 Gérer les données

Ce JSON servira à alimenter l'app de combat (séance suivante). C'est le vrai rôle de JSON : faire dialoguer deux programmes.

Où on va aujourd'hui

Hier, tu as fabriqué un monstre à la main. Aujourd'hui, on industrialise : on génère des monstres au hasard, mais pas n'importe comment — le design d'un monstre (sa couleur, ses yeux, ses cornes, ses crocs) va déterminer ses statistiques (PV et attaque). Un monstre à 3 yeux avec cornes et crocs sera plus fort qu'un petit à un œil. Puis on exporte l'équipe en JSON pour pouvoir, plus tard, la charger dans une autre application : l'arène de combat.

Schéma : design au hasard · couleur, yeux, cornes… · le design → les stats · PV, attaque · export JSON · → réutilisable dans l'arène · Le fil de la journée

Ce que tu sauras faire ce soir

NotionDans le générateur…
Objets, fonctions fléchéesdécrire un monstre, écrire les fonctions du générateur.
Math.randomtirer un design au hasard.
Une fonction qui calculefaire dépendre les stats du design (la règle du jeu).
Spread ...fusionner le design et ses stats en un seul monstre.
Tableaux, map/forEach/reduceconstituer une équipe, l'afficher, la résumer.
JSON (stringify/parse)exporter l'équipe pour une autre application.
Sprites animés (fournis)afficher des monstres qui bougent.

Chapitre 0.1 — Le projet fourni

Pré-requis

Un navigateur (Chrome/Firefox) et VS Code (ouvre le dossier : Fichier → Ouvrir le dossier). Récupère l'archive Generateur-equipe-projet-eleve.zip, décompresse-la, ouvre le dossier.

L'arborescence

generateur-equipe/ ├── index.html # la page (boutons, équipe, export) ├── styles.css # l'habillage ├── sprites.js # dessin ET animation des monstres ├── main.js # TON code (presque vide) └── README.md

Le rôle de chaque fichier

FichierContenuTu l'édites ?
index.htmlLa structure : boutons « Générer » / « Ajouter », la zone équipe, la zone d'export JSON. Déjà écrite.Non
styles.cssL'habillage clair (cartes, barres de stats, boutons). Déjà écrit.Non
sprites.jsLe moteur : dessinerMonstre(...) (pose fixe) et animerMonstre(...) (le monstre bouge).Non
main.jsTON fichier. Contient déjà COULEURS et des repères par étape.OUI

Chapitre 0.2 — Lancer & la console

Ouvrir

Double-clique sur index.html. La page s'ouvre : des boutons, une zone équipe vide, une zone d'export vide. Normal : rien n'est codé.

La console

F12, onglet Console. Tu dois lire :

Ce que tu dois voir
Base chargée. 6 couleurs. Ouvre le playbook !

Ta boucle de travail

1. j'écris dans main.js · 2. Ctrl+S · 3. je recharge (Ctrl+R) · 4. je regarde la page + la console.

1. Un monstre = un objet (le design)

On appelle design l'apparence d'un monstre : sa couleur, son nombre d'yeux, s'il a des cornes, des crocs. On range ça dans un objet.

Étape 1 — Un monstre d'essai

const design = {
  nom: "Zeb 1",
  couleurIndex: 0,   // position dans COULEURS (0 = la 1re)
  eyes: 2,
  horns: false,
  fangs: true,
};
console.log(design);

Étape 2 — L'afficher, animé

On va poser un canvas et demander à animerMonstre de dessiner le design. Ajoute temporairement dans index.html, sous les boutons : <canvas id="essai"></canvas>. Puis dans main.js :

const c = COULEURS[design.couleurIndex];
animerMonstre(document.querySelector("#essai"),
  { body: c.body, shade: c.shade, light: c.light, mouth: c.shade,
    eyes: design.eyes, horns: design.horns, fangs: design.fangs }, 6);

FLAG-A1

reconnais ton monstre

Règle le design d'essai pour obtenir : couleur n°4, 3 yeux, cornes, pas de crocs. Recharge, vérifie visuellement. Puis affiche console.log("FLAG-A1-" + (design.couleurIndex + design.eyes)) et recopie la valeur.

0 sur 8 dans cette étape

2. Un design AU HASARD

On veut que l'ordinateur invente le design. Outil : Math.random().

console.log(Math.floor(Math.random() * 6));   // un entier de 0 à 5

Étape 1 — Un compteur pour les noms

let compteur = 0;   // en haut de main.js

Étape 2 — La fonction qui invente un design

const designAleatoire = () => ({
  nom: "Zeb " + (++compteur),
  couleurIndex: Math.floor(Math.random() * COULEURS.length),
  eyes: 1 + Math.floor(Math.random() * 3),   // 1, 2 ou 3
  horns: Math.random() < 0.5,                // vrai 1 fois sur 2
  fangs: Math.random() < 0.6,
});
console.log(designAleatoire());

FLAG-D1

investigation

Pourquoi Math.floor et pas Math.round pour tirer un index de tableau ? Teste Math.round(Math.random()*3) : quelles valeurs peut-il sortir, et pourquoi est-ce un problème (indice : un index 3 dans un tableau de 3 cases) ? Réponds : FLAG-D1-…

0 sur 8 dans cette étape

3. Le design DÉCLENCHE les stats

Le cœur de la journée : on ne tire pas les stats au hasard séparément — c'est le design qui les calcule. On invente une règle du jeu : plus d'yeux, des cornes, des crocs = plus fort.

La règle

La fonction

const statsDuDesign = (m) => {
  const attaque = 2 + m.eyes + (m.fangs ? 3 : 0) + (m.horns ? 2 : 0);
  const pv = 24 + m.eyes * 4 + (m.horns ? 10 : 0);
  return { attaque, pv, pvMax: pv };
};

console.log(statsDuDesign({ eyes: 3, horns: true, fangs: true }));
Ce que tu dois voir
▶ {attaque: 10, pv: 46, pvMax: 46}

FLAG-B1

équilibre le jeu

Un monstre minimal (1 œil, ni cornes ni crocs) a quelle attaque ? Un maximal (3 yeux, cornes, crocs) ? Calcule les deux à la main, vérifie avec la fonction, et propose une modification du barème que tu trouves plus juste. Rends tes chiffres + ta modif. FLAG-B1-OK

0 sur 8 dans cette étape

4. Assembler : un monstre complet

Un monstre = un design + ses stats. On les fusionne avec le spread.

const monstreAleatoire = () => {
  const design = designAleatoire();
  return { ...design, ...statsDuDesign(design) };
};

console.log(monstreAleatoire());
Ce que tu dois voir
▶ {nom:"Zeb 1", couleurIndex:2, eyes:3, horns:true, fangs:false,
   attaque:7, pv:46, pvMax:46}

5. Afficher une carte (animée)

Une carte par monstre : le sprite animé, le nom, deux barres (PV, attaque), et les traits.

Les repères de la page

const equipeEl = document.querySelector("#equipe");
const PV_MAX = 50, ATT_MAX = 12;   // pour calibrer la largeur des barres

La fonction carte

const carte = (m) => {
  const c = COULEURS[m.couleurIndex];
  const traits = [m.eyes + (m.eyes > 1 ? " yeux" : " oeil"),
                  m.horns ? "cornes" : null,
                  m.fangs ? "crocs" : null].filter(Boolean).join(" · ");

  const div = document.createElement("div");
  div.className = "unit";
  div.innerHTML =
    '<canvas></canvas>' +
    '<div class="nom">' + m.nom + '</div>' +
    '<div class="stat"><span class="lab">PV</span><div class="track"><div class="fill pv" style="width:' + (m.pv/PV_MAX*100) + '%"></div></div><span class="val">' + m.pv + '</span></div>' +
    '<div class="stat"><span class="lab">ATT</span><div class="track"><div class="fill att" style="width:' + (m.attaque/ATT_MAX*100) + '%"></div></div><span class="val">' + m.attaque + '</span></div>' +
    '<div class="traits">' + traits + '</div>';

  equipeEl.appendChild(div);
  animerMonstre(div.querySelector("canvas"),
    { body:c.body, shade:c.shade, light:c.light, mouth:c.shade,
      eyes:m.eyes, horns:m.horns, fangs:m.fangs }, 5);
};

6. Une équipe (tableau + boutons)

Le tableau et l'affichage

let equipe = [];

const afficher = () => {
  equipeEl.innerHTML = "";        // on vide
  equipe.forEach(carte);         // une carte par monstre
};

Les boutons

document.querySelector("#btnGen").addEventListener("click", () => {
  compteur = 0;
  equipe = [1, 2, 3, 4].map(() => monstreAleatoire());   // 4 monstres
  afficher();
});

document.querySelector("#btnAdd").addEventListener("click", () => {
  equipe.push(monstreAleatoire());
  afficher();
});

FLAG-C1

le bug du forEach

Remplace un instant equipeEl.innerHTML = "" par rien (supprime la ligne). Génère plusieurs fois : que se passe-t-il, et pourquoi ? Remets la ligne, explique en une phrase à quoi elle sert. FLAG-C1-…

0 sur 8 dans cette étape

7. Résumer l'équipe (reduce)

Sous l'équipe, on affiche un bilan : nombre de monstres, PV total, attaque moyenne. Outil : reduce.

const resumeEl = document.querySelector("#resume");

// à la fin de afficher() :
  const totalPv = equipe.reduce((s, m) => s + m.pv, 0);
  const totalAtt = equipe.reduce((s, m) => s + m.attaque, 0);
  const moyAtt = equipe.length ? (totalAtt / equipe.length).toFixed(1) : 0;
  resumeEl.innerHTML = "Équipe de <b>" + equipe.length + "</b> monstres · " +
    "<b>" + totalPv + "</b> PV au total · attaque moyenne <b>" + moyAtt + "</b>";

FLAG-A2

la puissance de l'équipe

Ajoute une ligne au résumé : la puissance = PV total + (attaque totale × 5), calculée avec reduce. Génère une équipe et recopie : FLAG-A2-<la puissance>.

0 sur 8 dans cette étape

8. Analyser l'équipe (find, filter)

Deux méthodes très utiles pour interroger une collection.

const plusFort = equipe.reduce((max, m) => m.attaque > max.attaque ? m : max);
console.log("Le plus fort :", plusFort.nom, plusFort.attaque);

const cornus = equipe.filter((m) => m.horns);
console.log(cornus.length, "monstre(s) à cornes");

const premier3yeux = equipe.find((m) => m.eyes === 3);
console.log(premier3yeux ? premier3yeux.nom : "aucun à 3 yeux");

9. Exporter l'équipe en JSON

On veut sortir l'équipe du programme sous une forme réutilisable ailleurs. Le format universel : le JSON.

JSON, c'est quoi

const texte = JSON.stringify(equipe, null, 2);   // tableau d'objets -> texte
console.log(texte);

L'afficher dans la zone d'export

const jsonEl = document.querySelector("#json");

// à la fin de afficher() :
  jsonEl.value = JSON.stringify(equipe, null, 2);

Le bouton Copier

document.querySelector("#btnCopy").addEventListener("click", (e) => {
  jsonEl.select();
  navigator.clipboard.writeText(jsonEl.value);
  e.target.textContent = "Copié !";
  setTimeout(() => { e.target.textContent = "Copier le JSON"; }, 1200);
});

10. Le pont : réimporter (parse)

Pour comprendre l'aller-retour : l'opération inverse de stringify est parse. C'est ce que fera l'app de combat.

const texte = jsonEl.value;              // le JSON (texte)
const equipeChargee = JSON.parse(texte); // -> un vrai tableau d'objets
console.log(equipeChargee[0].nom, equipeChargee[0].attaque);

FLAG-D2

l'aller-retour

Copie le JSON de ton équipe, colle-le dans une variable const test = `…` (entre accents graves), fais JSON.parse(test) et affiche le nom du 2ᵉ monstre. Ça marche ? Note ce que tu observes. FLAG-D2-OK

0 sur 8 dans cette étape

11. Sous le capot : l'animation

Tu utilises animerMonstre depuis ce matin. Voyons comment il fait bouger un dessin (chapitre bonus, formateur en 2e année). Ouvre sprites.js.

Une image dépend du temps

const dy = Math.round(Math.sin(t / 380));   // -1, 0 ou 1 : le flottement
const clin = (t % 2600) < 130;              // vrai brièvement : le clignement

Une boucle qui redessine

function _tick(t) {
  // pour chaque monstre animé : redessine-le à l'instant t
  requestAnimationFrame(_tick);   // ... et recommence à la prochaine image
}

FLAG-E1

règle l'animation

Dans sprites.js, change le 380 (vitesse du flottement) et le 2600 (fréquence du clignement) et observe. Trouve un réglage que tu aimes, note tes valeurs. FLAG-E1-OK

0 sur 8 dans cette étape

Grand défi — pour les plus rapides

Tout fini ? Voici une modification lourde, en autonomie, sans corrigé. Prends ton temps.

Deux idées ambitieuses (choisis-en une)

Aucun corrigé : c'est un vrai morceau de dev. Si tu le mènes au bout, montre-le. On réutilisera ces équipes JSON quand on codera l'arène de combat.

On fait le point

Mini-quiz (corrigé dessous)

Exercice Réussi À revoir

Voir le corrigéMasquer le corrigé de l'exercice
  1. Les stats (PV, attaque) sont calculées à partir du design (yeux, cornes, crocs), pas tirées au hasard à part. 2. Fusionner design et stats en un seul monstre. 3. stringify : objet → texte (envoyer/stocker) ; parse : texte → objet (exploiter). 4. Sinon les anciennes cartes s'accumulent à chaque affichage. 5. Rappeler une fonction ~60 fois/s pour animer (redessiner à chaque image).

Tu avais trouvé ?

Ton générateur est complet si…

Compétences mobilisées (référentiel BTS SIO SLAM)

Livrable

Bloc 2 SLAM · Concevoir et développer une solution applicative
→ Développer des applications en respectant les standards de programmation
• Écrire du JavaScript moderne (ES6+) : objets, fonctions fléchées, spread
• Manipuler des collections avec map / forEach / filter / reduce
→ Gérer les données : sérialiser/désérialiser en JSON pour l'échange entre applications

0 sur 8 dans cette étape

TP JavaScript moderne (ES6+) · projet « Générateur d'équipe » · l'équipe exportée en JSON alimentera l'arène de combat (séance suivante).

TP terminé ?

Coche chaque livrable quand tu l'as : c'est la preuve que l'étape est acquise.

livrables
–
quiz réussi
–
de série
–
Voir tous les TP