Écrire un jeu en 2d avec Ruby et Gosu - partie 7
Ça fait plus de 2 mois que je dois terminer ce jeu et cette série d’article, alors au boulot !
Pour cette nouvelle version je voudrais ajouter une musique différente pour le game over. Et aussi pouvoir enfin recommencer une nouvelle partie après un game over.
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
Plusieurs musiques
Nous allons devoir gérer plusieurs musiques. Donnons leur des noms plus simple à manipuler que leurs paths :
module Song
GameOver = "assets/songs/In early time.ogg"
Level1 = "assets/songs/Around the Bend.ogg"
end
Et avec quoi écoute-t-on de la musique ? Avec un song player :
class SongPlayer
def play(file)
@song.stop if @song
@song = Gosu::Song.new(file)
@song.volume = 0.25
@song.play(true)
end
end
Dans la classe Window
on remplace l’ancienne manière de jouer une musique :
@song = Gosu::Song.new("assets/songs/Around the Bend.ogg")
@song.volume = 0.25
@song.play(true)
par notre nouvelle abstraction :
@song_player = SongPlayer.new
@song_player.play(Song::Level1)
N’oubliez pas d’ajouter les require qui vont bien dans le fichier main.rb
:
require_relative 'song'
require_relative 'song_player'
Trouver un bon endroit où mettre le code pour changer la musique après un
game over n’est pas si
évident que ça. Le moment où l’on capte que le jeu est dans l’état game over est
la méthode update_player
:
def update_player
@player.update(@items)
@game_over = true if @player.lives <= 0
end
Et il semblerait vraiment bizarre de modifier la musique alors qu’on est sensé mettre à jour le joueur. Autrement dit, le code suivant ne me plait pas :
def update_player
@player.update(@items)
if @player.lives <= 0
@game_over = true
@song_player.play(Song::GameOver)
end
end
À bien y réfléchir, le problème vient d’avant. On ne devrait pas changer l’état
de @game_over
ici, mais plutôt dans la méthode update
:
class Window < Gosu::Window
def update
return if @game_over
@game_over = true if @player.lives <= 0
update_items
update_player
end
def update_player
@player.update(@items)
end
end
Changer la musique se fera donc de cette manière :
def update
return if @game_over
if @player.lives <= 0
@game_over = true
@song_player.play(Song::GameOver)
end
update_items
update_player
end
Après extraction d’une nouvelle méthode, nous obtenons un code plus clair :
def update
return if @game_over
update_game_over
update_items
update_player
end
def update_game_over
return unless @player.lives <= 0
@game_over = true
@song_player.play(Song::GameOver)
end
Nouvelle partie
Ok, il est temps maintenant de pouvoir jouer une nouvelle partie après un game over. Pour cela, il faut regarder si le joueur appuie sur la touche espace pendant l’état game over, et dans ce cas faire un reset :
def update
reset if @game_over && Button.space?
return if @game_over
update_game_over
update_items
update_player
end
On peut tout de suite extraire une méthode new_game?
:
def update
reset if new_game?
# [...]
end
def new_game?
@game_over && Button.space?
end
On peut maintenant réfléchir à la méthode reset
, qui a son tour appellera
la méthode reset
du joueur. Ces deux méthodes sont évidentes :
class Window < Gosu::Window
def reset
@items = []
@player.reset
@song_player.play(Song::Level1)
@game_over = false
end
end
class Player
def reset
@score = 0
@lives = 3
@angle = 0.0
@velocity = 0.0
end
end
Pour terminer cette version, on va ajouter un message «press space to start» qui bouge pour attirer l’attention. Pour ça, on varie régulièrement d’une petite quantité la coordonnée y du message.
class UI
# ...
PressSpaceLow = 210
PressSpaceHigh = 270
def initialize
# ...
@y = 240
@y_velocity = -0.3
end
private
def draw_game_over
@big_font.draw_rel("Game Over", WindowWidth / 2, WindowHeight / 3,
ZOrder::UI, 0.5, 0.5)
@big_font.draw_rel("Press Space To Start", WindowWidth / 2, y,
ZOrder::UI, 0.5, 0.5)
end
def y
@y += y_velocity
end
def y_velocity
if @y < PressSpaceLow || @y > PressSpaceHigh
@y_velocity = -@y_velocity
end
@y_velocity
end
end
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
│ │ └── In early time.ogg
│ └── sound
│ ├── collect.wav
│ └── life-lost.wav
├── button.rb
├── main.rb
├── player.rb
├── smiley.rb
├── song_player.rb
├── song.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.7.0.