Ok : ajoutons un 3e niveau de difficulté :
enum class Difficulty : uint8_t {
easy,
medium,
hard
};
Difficulty
est une énumération, qui définit un nouveau type, et qui est composée d’un ensemble de valeurs constantes nommées, qu’on appelle des énumérateurs, et dont le type sous-jacent est uint8_t
.
À chaque nom d’une énumération est assignée une valeur entière qui correspond à sa place dans l’ordre des valeurs de l’énumération. Par défaut, la première valeur est 0, la suivante 1, et ainsi de suite.
Mais on peut tout à fait définir explicitement la valeur d’un énumérateur.
Autrement dit, on pourrait aussi écrire les choses ainsi :
enum class Difficulty : uint8_t {
easy = 0,
medium = 1,
hard = 2
};
On peut également choisir de leur affecter des valeurs arbitraires :
enum class Difficulty : uint8_t {
easy = 2,
medium = 4,
hard = 8
};
Dans notre cas, il est plus intéressant de conserver les valeurs entières contigües affectées par défaut :
enum class Difficulty : uint8_t {
easy,
medium,
hard
};
Donc :
Difficulty::easy = 0
Difficulty::medium = 1
Difficulty::hard = 2
Pourquoi ? Parce-ce qu’on va justement se servir de ces valeurs entières pour positionner le curseur de sélection du niveau de difficulté :
gb.display.fillRect(20, 31 + 10*(uint8_t)game.difficulty, 4, 4);
L’expression (uint8_t)game.difficulty
permet justement d’obtenir la valeur entière associée à l’énumérateur stocké dans la variable game.difficulty
.
Ceci permet donc d’obtenir l’une des valeurs 0
, 1
ou 2
. Par conséquent, selon la valeur entière sous-jacente de game.difficulty
on obtient l’un des 3 positionnements suivants. :
gb.display.fillRect(20, 31, 4, 4); // pour Difficulty::easy
gb.display.fillRect(20, 41, 4, 4); // pour Difficulty::medium
gb.display.fillRect(20, 51, 4, 4); // pour Difficulty::hard
Pratique, nan ?
Maintenant, pour implémenter la gestion du curseur de sélection, il existe plusieurs façons de le faire, en jouant sur les énumérateurs. Mais je préfère te donner la plus simple d’entre elles, puisque tu débutes ton apprentisssage du C++. Les autres font intervenir des notions plus avancées qui ne sont pas triviales
void menu() {
if (gb.buttons.pressed(BUTTON_UP)) {
switch (game.difficulty) {
case Difficulty::medium: game.difficulty = Difficulty::easy; break;
case Difficulty::hard: game.difficulty = Difficulty::medium;
}
} else if (gb.buttons.pressed(BUTTON_DOWN)) {
switch (game.difficulty) {
case Difficulty::easy: game.difficulty = Difficulty::medium; break;
case Difficulty::medium: game.difficulty = Difficulty::hard;
}
} else if (gb.buttons.pressed(BUTTON_A))
game.state = State::play;
gb.display.print(6, 10, "SELECT DIFFICULTY");
gb.display.print(32, 30, "EASY");
gb.display.print(32, 40, "MEDIUM");
gb.display.print(32, 50, "HARD");
gb.display.fillRect(20, 31 + 10*(uint8_t)game.difficulty, 4, 4);
}
L’inconvénient ici réside dans le fait d’avoir à modifier les règles de changement de valeur de game.difficulty
dès lors que tu ajoutes un nouvel énumérateur (donc un nouveau niveau de difficulté), ou bien que tu en retires un. Mais pour un petit ensemble d’énumérateurs, ça reste assez facile à gérer.
Enfin, pour répondre à ta dernière question :
Note que gb.frameCount
n’est pas une fonction, mais un attribut (une propriété) de l’objet gb
.
Par exemple, si on souhaite simplement modifier la couleur du curseur de sélection tous les 8 frames, on peut implémenter ça ainsi :
uint8_t phase = gb.frameCount % 24;
if (phase < 8) gb.display.setColor(BLUE);
else if (phase < 16) gb.display.setColor(WHITE);
else gb.display.setColor(RED);
gb.display.fillRect(20, 31 + 10*(uint8_t)game.difficulty, 4, 4);
- quand
phase
est compris entre0
et7
, le curseur passe au bleu, - quand
phase
est compris entre8
et15
, le curseur passe au blanc, - quand
phase
est compris entre16
et23
, le curseur passe au rouge.
Est-ce que ça répond à ta question ? Ne sachant pas ce que tu entends par “modifier un élément graphique”, j’ai pris cet exemple au hasard, mais tu pensais peut-être à autre chose ?