Écrire un jeu en 2d avec Ruby et Gosu - partie 5
Aujourd’hui on ajoute de la musique de fond, on s’intéresse à ce qui se passe quand on perd une vie, et on écrit un beau «Game Over» quand on a perdu toutes les vies.
La totalité des articles:
- Installation de Gosu, affichage d’images statiques
- Déplacer le joueur et pluie de smileys
- Beep, fonte et collecte des smileys
- On s’occupe des vies
- Musique et game over
- Affichage selon un angle
- Plusieurs musiques et reset de la partie
De la musique
Ajouter une musique de fond est très simple avec Gosu. On crée la ressource
comme on a créé des sons ou des images. Ensuite on règle le volume entre
0 et 1. Et enfin on appuie sur play
:
Le paramètre true
passé à la méthode play
lui indique qu’on veut jouer la
musique en boucle.
Un paramètre booléen est ce que j’appelle un «paramètre de contrôle» (Martin Fowler appelle ça un Flag argument. C’est un bon vieux code smell et je suis un peu déçu de trouver ça dans Gosu. Surtout qu’il est ici facile de s’en débarrasser en proposant deux méthodes sans paramètres, par exemple
play
etloop
.
Petite pause quand on perd une vie
Pour marquer le coup, je voudrais que le jeu pause pendant un certain temps (ici une seconde et demi) quand le joueur perd une vie. Voici d’abord le code, puis les explications:
Commençons par ce qui change dans collision
. Lorsque le joueur entre en
collision avec un smiley à l’envers, j’enregistre l’instant de cette collision.
Gosu::milliseconds
retourne le nombre de millisecondes écoulées depuis le
début du jeu.
Pour savoir si le joueur vient de perdre une vie, la méthode just_lost_a_life?
compare le temps présent (Gosu::milliseconds
) avec l’instant où le joueur a
perdu une vie (@lost_life_at
). Si la différence est de moins de 1500
millisecondes (une seconde et demi) just_lost_a_life?
retournera true
.
Lors de l’initialisation on trouve cette ligne:
@lost_life_at = -20_000
… qui est nécessaire pour que @lost_life_at
ne soit pas nil
au début
du jeu, ce qui provoquerait une erreur dans just_lost_a_life?
. Mais pourquoi
-20,000 ? Essayez de la définir à zéro pour voir… En fait -20,000 est une
valeur arbitraire, qui aurait aussi bien pu être -10,000 ou -9999, etc.
Une autre solution aurait été d’écrire just_lost_a_life?
comme ceci:
Mais j’aime moins cette solution, pour deux raisons, 1) c’est moins performant puisqu’on a un test de plus à chaque update (ok c’est pas grand chose, mais ça plus ça plus ça…, et là c’est très facilement évitable pour rien) et 2) je préfère que toutes les variables d’objets soient définies dans le constructeur (peut-être un vieux reste de mon passé de javaïste, ou un truc comme ça).
Quoiqu’il en soit, la ligne @lost_life_at = -20_000
mérite un commentaire
expliquant la raison de cette valeur arbitraire. J’espère que ce sera
compréhensible:
Pour que tout ceci fonctionne, il suffit maintenant d’esquiver les updates au bon moment:
Game over quand 0 vies
Vous avez maintenant compris que j’avance par petites itérations successives, qui ne sont d’ailleurs pas toujours des fonctionnalités complètes. Cette fois on va afficher «Game Over» et geler le jeu quand le joueur atteint zéro vies:
Ce qui mérite des explications c’est ce nouveau game_state
. Plutôt que
d’envoyer les informations à l’UI sous la forme @ui.draw(@player, @game_over)
je préfère envoyer un état du jeu. Tout d’abord je n’envoie que le nécessaire
et ensuite on a un seul paramètre et non pas une liste de paramètres condamnée
à enfler.
Reste à refléter ça dans la classe UI:
La nouveauté est la méthode draw_rel
, qui va écrire son texte
relativement à lui-même. Oui je sais, ça sonne bizarre. Mais si vous
essayez les valeurs 0 et/ou 1 à la place de 0.5, vous devriez vite comprendre.
Là on va centrer le texte autour du milieu de l’écran, à la fois
horizontalement et verticalement.
Le fait que
draw_rel
soit l’abréviation dedraw_relative
ne sautera pas forcement aux yeux de tout le monde. Alors pourquoi avoir utilisé une abréviation ?
Pour finir, voici le contenu du jeu pour l’instant:
$ tree
.
├── assets
│ ├── fonts
│ │ └── VT323
│ │ ├── OFL.txt
│ │ └── VT323-Regular.ttf
│ ├── images
│ │ ├── background.png
│ │ ├── heart.gif
│ │ ├── player.png
│ │ ├── smiley-green.png
│ │ └── smiley-yellow.png
│ ├── songs
│ │ └── Around the Bend.ogg
│ └── sound
│ ├── collect.wav
│ └── life-lost.wav
├── main.rb
├── player.rb
├── smiley.rb
├── ui.rb
├── window.rb
└── z_order.rb
Le code et les assets se trouvent sur Github. La version précise pour cet article est la version 0.5.0.