❤ 1Gari Domaine : RGSS
Niveau : Moyen
Requis : Avoir compris mes 2 précédents tutos, ici et ici.
Vous voulez un menu... avec un curseur pour vos choix et vous n'avez pas envie de faire ça avec des events...(comme je vous comprends).... alors ce tuto est fait pour vous.^^
Je vous expliquerai de manière générale le fonctionnement des fenêtre à choix.
Première chose !
Lors de la définition de votre classe Window_x_menu...
Ce n'est plus "< Window_Base" mais "< Window_Selectable" qu'il faudra inscrire, comme ceci:
1
2
3
| class Window_x_menu < Window_Selectable
....
end |
Bon déjàj une chose de faite....
Mais comment çà marche ?
Prenons un cas concret :
Citation: Nous voulons que notre Scene_xxxx n'affiche une certaine fenêtre que si un choix est fait et un menu, le choix de ce menu fait changer la fenêtre affichée...
- Nos choix sont "Option 1", "Option 2", et "Option 3"
- Les 3 fenêtre doivent être de classe différente ( pour complexifier un peu notre histoire)
- Quand j'appuie sur la touche B ou au bout d'un certain temps d'inactivité, je dois retourner à la map. |
1ère étape, la définition des classes de fenêtre "statique"
Chacune d'elle doit afficher "Prout 1" ou 2 ou 3 selon l'option choisie !
Donc nous savons que notre écran de jeu fait 640 par 480 pixel. Essayons d'utiliser au mieux l'espace...
Je suggère, dans notre cas, qu'un menu horizontal sera mieux... Mais pas de souci , nous ferons aussi un menu vertical.
Bref... Prévoyons notre espace pour le menu -> tout en haut 640 de large, sur 64 de haut. Il nous reste donc 480 - 64 = 416 pixel. Donc nos 3 fenêtres feront 640*416 pixel.
Leurs positions seront donc en 0,64 puisque en 0,0 il y aura le menu.
Passons au code maintenant !
Pour la fenêtre 1:
1
2
3
4
5
6
7
8
9
10
11
| class Window_f1 < Window_Base
def initialize
super(0,64,640,416)
self.contents = Bitmap.new(width - 32, height - 32)
refresh
end
def refresh
self.contents.clear
self.contents.draw_text(10, 10, 200, 32, "Prout 1 !!",0)
end
end |
Pour la fenêtre 2 :
1
2
3
4
5
6
7
8
9
10
11
| class Window_f2 < Window_Base
def initialize
super(0,64,640,416)
self.contents = Bitmap.new(width - 32, height - 32)
refresh
end
def refresh
self.contents.clear
self.contents.draw_text(10, 10, 200, 32, "Prout 2 !!",1)
end
end |
Pour la fenêtre 3 :
1
2
3
4
5
6
7
8
9
10
11
| class Window_f3 < Window_Base
def initialize
super(0,64,640,416)
self.contents = Bitmap.new(width - 32, height - 32)
refresh
end
def refresh
self.contents.clear
self.contents.draw_text(10, 10, 200, 32, "Prout 3 !!",2)
end
end |
Nos 3 fenêtres sont définies ; plutôt rapide n'est ce pas !! ( vive le copier coller !)
Maintenant ce qui nous intéresse le plus, le menu : nous le voulons horizontal et il n'a que 3 options, ca nous donne donc... 3 colonnes !
Voici le code de cette fenêtre de menu.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| class Window_menu < Window_Selectable
def initialize()
super(0, 0, 640, 64)
@column_max = 3
@item_max = 3
@commands = ["Option 1","Option 2","Option 3"]
self.contents = Bitmap.new(width - 32, @item_max * 32)
refresh
self.index = 0
end
def refresh
self.contents.clear
for i in 0...@item_max
draw_item(i, normal_color)
end
end
def draw_item(index, color)
self.contents.font.color = color
rect = Rect.new(4, 32 * index, self.contents.width - 8, 32)
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
self.contents.draw_text(rect, @commands[index])
end
end |
On a trois fonctions de base, on en reconnait deux déjà étudiées dans le tutorial précédent.
Mais sur lesquelles nous allons revenir, parce qu'il y a des détails propres aux fenêtres à choix, dans ces fonctions.
Donc commençons par "Initialize"
On reconnaît la commande super pour les dimensions et coordonnées de la fenêtre... puis 3 variables d'instance, très importantes !
- @column_max définit le nombre de colonne dans la fenêtre et donc, par un astucieux calcul le nombre de ligne... bref à changer à votre guise, donc pour un menu vertical -> 1 seule colonne, et horizontal... ben essayez de trouver un nombre de colonne adéquat réduisant suffisament le nombre de lignes.
- @item_max définit le nombre d'objets, enfin de truc à afficher, comme option.
- @commands définit un tableau contenant chacune de ces options, qui sont des chaines de caractères.
On définit ensuite notre bitmap. Vous remarquerez que sa hauteur est calculée en fonction du nombre d'objets. (on aurait pu laisser height - 32 parce que notre menu ne fait qu'une seule "ligne".)
Puis est appelé refresh, et enfin on spécifie la position d'origine du curseur !
C'est pas très compliqué : la valeur correspond à la position dans le tableau. On commence donc à 0 et on finit à 2 si il y a 3 choix, et ainsi de suite. Ici notre curseur sera sur "Option 1".
Si on voulait le curseur sur la dernière de nos trois options, cela donnerait self.index = 2. Et si on ne veut pas qu'il s'affiche, on lui donne la valeur -1, le menu sera alors non navigable. Il faut donc que la valeur d'index soit >= 0 pour qu'il le soit.
Passons à refresh !
On a une petite boucle après "le nettoyage" du bitmap... qui va de 0 à 2
pour chacun de ses passages, on affiche l'option d'index i, avec la couleur normale (cf tuto précédent).
On affiche grâce à la 3e méthode draw_item(index,color) qui a donc 2 paramètres : l'index et la couleur.
On définit donc la couleur de police avec le 2ème paramètre, puis on crée un rectangle vide dans lequel on appliquera le texte... Ca permet d'avoir des options bien alignées, qui dépassent pas et tout...
Vous remarquerez que draw_item est complètement différent au niveau des paramètres que celle expliqué dans le tuto précédent... ici on a que 2 paramètres au lieu des 6 vus précédemment.
Pourquoi ? Parce que le rectangle qui lui est passé en paramètre, remplace les 4 premiers (il définit une position et 2 dimensions), et le 6ème pour l'alignement est omis volontairement (donc par défaut =0 pour aligner à gauche).
Ici le 2e paramètre correspond au 5e de la méthode expliquée dans la partie 1, c'est à dire la chaîne de caractère affichée.
On récupère la valeur d'index "index" du tableau @commands. On obtiendra donc grâce à la boucle successivement Option 1, Option 2 et Option 3.
Voilà Pour la fenêtre de choix ! C'est pas très compliqué !
Allez passons à notre Scene_xxxx qui doit gérer tout ça !!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| class Scene_xxxx
def main
# Création des différentes fenêtres
@fenetre1 = Window_f1.new
@fenetre2 = Window_f2.new
@fenetre3 = Window_f3.new
@menu = Window_menu.new
# Paramétrage des différents fenêtres
@fenetre1.visible = false
@fenetre2.visible = false
@fenetre3.visible = false
Graphics.transition
loop do
Graphics.update
Input.update
update
if $scene != self
break
end
end
Graphics.freeze
@fenetre1.dispose
@fenetre2.dispose
@fenetre3.dispose
@menu.dispose
end
#-----------------------
def update
@fenetre1.update
@fenetre2.update
@fenetre3.update
@menu.update
@temp == nil ? @temp=0 : @temp+=1
if Input.trigger?(Input::B) or @temp>=50
$scene= Scene_Map.new
return
end
if Input.trigger?(Input::C)
case @menu.index
when 0
@fenetre1.visible = true
@fenetre2.visible = false
@fenetre3.visible = false
when 1
@fenetre1.visible = false
@fenetre2.visible = true
@fenetre3.visible = false
when 2
@fenetre1.visible = false
@fenetre2.visible = false
@fenetre3.visible = true
end
@temp=0
end
end
end |
Au départ on a donc que le menu ! avec le curseur sur option 1 et aucune fenêtre affichée !!
Pourquoi ?? parce que j'ai mis leur attribut "visible" sur false (faux) dès le départ. J'aurais très bien pu aussi le faire directement dans le initialize de chacune d'elle, ce qui aurait donné ceci :
1
2
3
4
5
| class ....
def initialize
....
self.visible = false
... |
Bon j'ai défini une variable de temporisation (@temp) qui si elle est nulle (n'a donc aucune valeur, même pas 0) devient égale à zéro et sinon, augmente de 1. Comme on le sait, cette méthode update est appelée à chaque frame ; donc la première fois on définit @temp à 0... puis la frame suivante elle sera égale à 1... puis à 2 ... etc
Quand arrive 50 ou un appuie sur la touche B (Echap), on change la valeur de $scene en mettant = Scene_Map.new, qui correspond donc à la Map.
SI j'appuie sur C (Entrée ou Espace), selon la valeur de l'index du menu, donc de la position du curseur, je change la visibilité de la fenêtre voulue. Et je remets @temp = 0 pour remettre la temp à Zéro... et dire que j'ai pas été inactif....
Voilà, notre cas est réalisé !
Bon maintenant légère variante....
On veut le menu inactif ! et sans curseur affiché tant que j'ai pas appuyé sur la touche C une première fois !
Puis ensuite je peux afficher les fenêtres !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
| class Scene_xxxx
def main
# Création des différentes fenêtres
@fenetre1 = Window_f1.new
@fenetre2 = Window_f2.new
@fenetre3 = Window_f3.new
@menu = Window_menu.new
# Paramétrage des différents fenêtres
@fenetre1.visible = false
@fenetre2.visible = false
@fenetre3.visible = false
@menu.active = false
@menu.index = -1
Graphics.transition
loop do
Graphics.update
Input.update
update
if $scene != self
break
end
end
Graphics.freeze
@fenetre1.dispose
@fenetre2.dispose
@fenetre3.dispose
@menu.dispose
end
#-----------------------
def update
@fenetre1.update
@fenetre2.update
@fenetre3.update
@menu.update
@temp == nil ? @temp=0 : @temp+=1
if Input.trigger?(Input::B) or @temp>=50
$scene= Scene_Map.new
return
end
if Input.trigger?(Input::C)
if @menu.active == false
@menu.index = 0
@menu.active = true
return
end
case @menu.index
when 0
@fenetre1.visible = true
@fenetre2.visible = false
@fenetre3.visible = false
when 1
@fenetre1.visible = false
@fenetre2.visible = true
@fenetre3.visible = false
when 2
@fenetre1.visible = false
@fenetre2.visible = false
@fenetre3.visible = true
end
@temp=0
end
end
end |
Donc on a spécifié au départ que la fenêtre menu est active à false (ça bloque la navigation, et l'index à -1 pour cacher le curseur). On aurait pu faire ça dans le Initialize de Window_menu en remplacant @menu par self.
Ensuite dans le Update :
A l'endroit où je teste la touche C, je vérifie avant le test de la position du curseur, que le menu est actif ou pas, et s'il ne l'est pas, je l'active et j'affiche le curseur... ET je quitte update !! pour ne pas traiter le cas de la position du curseur qui est juste après !
Comme ça à la frame suivante mon menu est actif, avec le curseur à "option 1" et je n'ai plus qu'à appuyer sur C pour afficher la fenêtre voulue.
Si on avait omis le "return", comme on avait mis index à 0, on rentrait dans un des cas possible de l'affichage, et il aurait donc affiché lors du premier appui la fenêtre 1 au lieu de ne le faire qu'au second !
Voili voulou !! J'espère que vous avez compris !!!
Mis à jour le 8 novembre 2020.
|