Sujet: Cours # 6 : Window_Selectable et scene complexe. Mar 10 Fév 2009 - 18:03
Niveau : Intermédiaire. Prérequis : Les 4 cours sur le Ruby + le cours # 5 sur le RGSS2. Outils : Créer un nouveau projet vierge RMVX comme si vous vouliez commencer un nouveau jeu. Sujets traités : Window_Selectable et scene complexe.
Dans le cours # 5, nous avons appris à faire des scenes et des windows, ainsi qu'à utiliser Window_Command. Dans ce cours, nous allons apprendre comment fonctionne une Window_Selectable, ce qui nous permettra de faire des scenes de plus en plus complexe.
Cours :
Etude de Window_Selectable :
Window_Selectable est une classe spécilament conçu pour permettre de créer des fenetres de choix. Window_Command ( les listes ) est une sous-classe de Window_Selectable. Les fenetres de choix d'objets, de competences ou les choix multiples de la commande d'event "Faire un choix" hérite egalement de Window_Selectable.
Code:
class Window_Selectable < Window_Base #-------------------------------------------------------------------------- # * Public Instance Variables #-------------------------------------------------------------------------- attr_reader :item_max # item count attr_reader :column_max # digit count attr_reader :index # cursor position attr_reader :help_window # help window #-------------------------------------------------------------------------- # * Object Initialization # x : window X coordinate # y : window Y coordinate # width : window width # height : window height # spacing : width of empty space when items are arranged horizontally #-------------------------------------------------------------------------- def initialize(x, y, width, height, spacing = 32) @item_max = 1 @column_max = 1 @index = -1 @spacing = spacing super(x, y, width, height) end # ... end
En plus de ce qui est commun à toutes les Window, Window_Selectable possede 4 variables d'instances.
"item_max" designe le nombre limite d'objet que contiendra la fenetre, donc par consequence le nombre maximum de choix qu'elle offrira. Lorsque vous utilisez une Window_Command, vous ne donnez pas de valeur à "item_max", elle prends automatiquement une valeur egale à la taille de votre tableau "commands". Mais lorsque vous créez une Window_Selectable, il vous faudra lui donner la valeur qui vous convient. ( Sinon, vous ne verrez qu'un choix de disponible ... )
"column_max" designe le nombre de colonne de votre fenetre. C'est quelque chose que nous avons déjà vu avec Window_Command. Le nombre total d'objet sera reparti en fonction du nombre de colonne. Il n'est necessaire d' indiquer une valeur que si le nombre de colonne est different de la valeur par defaut c'est-à-dire 1.
"index" designe la position du curseur. 0 designe le premier choix accessible. Le reglage par defaut est -1, c'est-à-dire que le curseur sera invisible. Cette "norme" est utilisé dans la plupart des scripts ( il faut que ce soit inferieur à 0, nous verrons pourquoi plus bas !! ).
"help_window" permet d'associer une deuxieme fenetre à votre Window. C'est généralement utilisé pour associer une fenetre d'aide, pour guider la selection du joueur. Tout est déjà pres reglé pour vous. A chaque deplacement du curseur, si vous avez determiné une fenetre associé, la methode "update_help" sera appelé. La seule chose que vous avez à faire, c'est donc de definir cette methode "update_help". ( Nous y reviendrons en detail )
Comme vous pouvez le constater, c'est 4 variables ont un attribut de lecture. Mais "index" et "help_window" peuvent etre modifié par une methode.
Code:
#-------------------------------------------------------------------------- # * Set Cursor Position # index : new cursor position #-------------------------------------------------------------------------- def index=(index) @index = index update_cursor call_update_help end
#-------------------------------------------------------------------------- # * Set Help Window # help_window : new help window #-------------------------------------------------------------------------- def help_window=(help_window) @help_window = help_window call_update_help end
Ce qui signifie que vous pouvez modifier le curseur ou determiner la fenetre associé depuis une autre classe. ( Donc dans la pratique, depuis votre scene !! ) "item_max" et "column_max", quand à elles, doivent etre defini dans "Window_Selectable".
Window_Selectable est préconçu pour gerer les deplacements du curseur de selection mais n'offre aucune methode particuliere consernant l'affichage. C'est pour cette raison que l'on n'utilise jamais une Window_Selectable mais toujours une Window spécifique héritant de Window_Selectable.
Lorsque tous les choix possibles apparaissent à l'ecran, c'est assez simple. La complexité vient lorsqu'il y a plus de choix que de place. En effet, il convient alors de calculer le defilement de la "fenetre". ( Guillemet car je ne parle pas de la fenetre d'un point de vue script mais d'un point de vue visuel )
Examinons la methode "update" de cette classe :
Code:
#-------------------------------------------------------------------------- # * Frame Update #-------------------------------------------------------------------------- def update super if cursor_movable? last_index = @index if Input.repeat?(Input::DOWN) cursor_down(Input.trigger?(Input::DOWN)) end if Input.repeat?(Input::UP) cursor_up(Input.trigger?(Input::UP)) end if Input.repeat?(Input::RIGHT) cursor_right(Input.trigger?(Input::RIGHT)) end if Input.repeat?(Input::LEFT) cursor_left(Input.trigger?(Input::LEFT)) end if Input.repeat?(Input::R) cursor_pagedown end if Input.repeat?(Input::L) cursor_pageup end if @index != last_index Sound.play_cursor end end update_cursor call_update_help end
Dans l'ensemble, c'est vraiment simple. Si le curseur peut etre bouger, on regarde quelles sont les touches actives. Pour chaque cas, on regarde où doit aller le curseur. S'il a effectivement bouger, petit sound_effect. On met à jour le curseur, on met à jour l'aide.
Ca n'est pas dans l'update que reside la complexité de cette classe mais dans les methodes qu'elle utilise.
Citation :
Avant d'aller plus loin, petite piqûre de rappel !! Le modulo ( symbole % ) est tres utilisé dans Window_Selectable. Cet operateur retourne le reste d'un quotient.
Souvenez vous de vos jeunes années. 6 / 4 = 1 et il reste 2 donc 6 % 4 = 2
Bon, généralement, la question qui vient juste apres est : A quoi ça sert ?
Par exemple, à determiner si un Integer est paire ou non. 6 % 2 = 0 => Paire 5 % 2 = 1 => Impaire
Dans notre cas, ça nous servira à convertir un index en rang et colonne : Notre index = 17 et nous avons 5 colonne : Où se trouve notre curseur ? C'est simple : rang = index / column_max => 3 column = index % column_max => 2 Notre curseur est au rang 3 et à la colonne 2.
Examinons d'abord les methodes "cursor_down", "cursor_up", "cursor_right" et "cursor_left" :
Code:
#-------------------------------------------------------------------------- # * Move cursor down # wrap : Wraparound allowed #-------------------------------------------------------------------------- def cursor_down(wrap = false) if (@index < @item_max - @column_max) or (wrap and @column_max == 1) @index = (@index + @column_max) % @item_max end end #-------------------------------------------------------------------------- # * Move cursor up # wrap : Wraparound allowed #-------------------------------------------------------------------------- def cursor_up(wrap = false) if (@index >= @column_max) or (wrap and @column_max == 1) @index = (@index - @column_max + @item_max) % @item_max end end #-------------------------------------------------------------------------- # * Move cursor right # wrap : Wraparound allowed #-------------------------------------------------------------------------- def cursor_right(wrap = false) if (@column_max >= 2) and (@index < @item_max - 1 or (wrap and page_row_max == 1)) @index = (@index + 1) % @item_max end end #-------------------------------------------------------------------------- # * Move cursor left # wrap : Wraparound allowed #-------------------------------------------------------------------------- def cursor_left(wrap = false) if (@column_max >= 2) and (@index > 0 or (wrap and page_row_max == 1)) @index = (@index - 1 + @item_max) % @item_max end end
Seul les fenetres d'une colonne autorise le passage du dernier rang au permier rang par le bas et reciproque, c'est ce que verifie la condition des methodes "cursor_up" et "cursor_down". Et on peut pas passer du dernier rang au premier par la droite et recirpoque, c'est ce que verifie la condition des methodes "cursor_right" et "cursor_left". Si le deplacement est possible, on ajuste le nouvel index. Le role du modulo est d'ajuster l'index en fonction du nombre maximum d'objet.
Code:
#-------------------------------------------------------------------------- # * Move cursor one page down #-------------------------------------------------------------------------- def cursor_pagedown if top_row + page_row_max < row_max @index = [@index + page_item_max, @item_max - 1].min self.top_row += page_row_max end end #-------------------------------------------------------------------------- # * Move cursor one page up #-------------------------------------------------------------------------- def cursor_pageup if top_row > 0 @index = [@index - page_item_max, 0].max self.top_row -= page_row_max end end
Les methodes "cursor_pagedown" et "cursor_pageup" permettent de passer d'une page à l'autre lorsqu'il y a beaucoup d'objets.
La methode "page_row_max" permet de savoir combien de rang il y a sur une page :
Code:
def page_row_max return (self.height - 32) / WLH end
Donc, la taille du bitmap ( la fenetre moins le cadre ) divisé par la hauteur d'un rang. ( La constante WLH defini dans Window_Base est egale à 24 ).
La methode "page_item_max" permet de savoir combien d'objets une page peut contenir au maximum.
Code:
def page_item_max return page_row_max * @column_max end
Donc, le nombre de rang d'une page multiplié par le nombre de colonne.
En fonction de cela, l'index est modifié, et la position des rangs est recalculé.
Tout cela ne sert qu'a determiner le nouvel index en fonction des Input. La position de curseur est calculé par une autre methode : "update_cursor".
Code:
#-------------------------------------------------------------------------- # * Update cursor #-------------------------------------------------------------------------- def update_cursor if @index < 0 # If the cursor position is less than 0 self.cursor_rect.empty # Empty cursor else # If the cursor position is 0 or more row = @index / @column_max # Get current row if row < top_row # If before the currently displayed self.top_row = row # Scroll up end if row > bottom_row # If after the currently displayed self.bottom_row = row # Scroll down end rect = item_rect(@index) # Get rectangle of selected item rect.y -= self.oy # Match rectangle to scroll position self.cursor_rect = rect # Refresh cursor rectangle end end
Si l'index est inferieur à 0 ( souvenez vous, l'index par defaut est -1 ), le curseur est vidé ( invisible donc ). Sinon, on ajuste les rangs du haut et du bas, on recupere un rectangle qui sera positionné sur l'objet actuel. Ce rectangle servira à créer le curseur. C'est la methode "item_rect" qui va determiner la position du curseur en fonction de l'index.
Code:
#-------------------------------------------------------------------------- # * Get rectangle for displaying items # index : item number #-------------------------------------------------------------------------- def item_rect(index) rect = Rect.new(0, 0, 0, 0) rect.width = (contents.width + @spacing) / @column_max - @spacing rect.height = WLH rect.x = index % @column_max * (rect.width + @spacing) rect.y = index / @column_max * WLH return rect end
La largeur du rectangle est calculé en fonction de la largeur de la fenetre et du nombre de colonne. Sa hauteur, c'est notre constante WLH qui la fixe ( je rappelle : 24 pixels ). La position x, c'est simplement la colonne de l'objet multiplié par la largeur du rectangle. La position y, c'est le rang multiplié par la hauteur d'un rang.
Maintenant que vous connaissez en detail le fonctionnement de Window_Selectable, il nous reste à jouer avec !!
Dernière édition par ASHKA le Mar 10 Fév 2009 - 18:06, édité 1 fois
ASHKA
Voyageur Lv.10
Age : 42 Inscrit le : 04/12/2008 Messages : 383
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Mar 10 Fév 2009 - 18:04
Utilisation de Window_Selectable :
On va commencer par créer la scene :
Code:
class Scene_Test < Scene_Base def start create_menu_background @win = Window_Test.new @help = Window_Help.new @win.help_window = @help end def terminate dispose_menu_background @win.dispose @help.dispose end def update update_menu_background @win.update if Input.trigger?(Input::B) Sound.play_cancel $scene = Scene_Map.new end end end
Les methodes "create_menu_background", "dispose_menu_background", "update_menu_background" servent à créer un Sprite qui aura l'apparence de la map actuel. Ces methodes sont notamment utilisés dans le menu. Si vous voulez connaitre leurs definitions, jetez un oeil à Scene_Base.
Evidement, Window_Test sera notre window héritant de Window_Selectable. On voit comment associer deux fenetres par l'intermediaire de la variable "help_window" des Window_Selectable. Il est important d'utiliser l'update de notre fenetre, comme pour les Window_Command. Rappellez vous, c'est elle qui va gerer l'input et le curseur.
Il est temps de s'interesser à notre fenetre :
Code:
class Window_Test < Window_Selectable def initialize w = 232 h = (4*24)+32 x = 272 - (w/2) y = 208 - (h/2) super(x, y, w, h) @column_max = 5 @spacing = 0 self.index = 0 refresh end def refresh @data = [] for x in 0...20 @data.push(x.to_s) end @item_max = @data.size create_contents for i in 0...@item_max draw_item(i) end end def draw_item(index) rect = item_rect(index) self.contents.clear_rect(rect) item = @data[index] if item != nil rect.width -= 4 self.contents.draw_text(rect, item, 1) end end def update_help @help_window.set_text("Vous etes sur le numero #{index}", 1) end end
Dans l'initialize, j'indique le nombre de colonne ( ici 5 ) et j'ai choisi de ne mettre aucun espace. La variable @spacing permet de mettre des espaces entre chaque objets. Sa valeur par defaut est de 32 pixels ce qui est assez elevé ( une ligne fait 24 pixels par exemple ). Pour le reste, c'est un copié/collé de Window_Item ( la fenetre de choix d'objet - menu ou combat ) légérement modifié pour coller à nos besoins. Quasiment toutes les fenetres basé sur Window_Selectable que vous verrez ( script de base ou ceux du Net ) suivent ce même schema. Evidement, rien ne vous oblige à faire la même chose, vous pouvez trouver votre propre façon de faire. Mais comme c'est ce qu'il y a de plus repandu, il faut bien vous expliquer comment ça fonctionne.
Dans la methode "refresh", on commence par remplir un tableau. Ici, il contient des String, dans Window_Item, il contient des objet RPG::Item, ça, c'est à vous de choisir !! La taille de notre tableau nous donne notre "item_max". Ce tableau contiendra donc tous nos choix.
Ensuite, on reconnait la methode "create_contents", souvenez vous, celle que nous avons du rajouter dans Window_Command. Puis, pour chaque element de notre tableau, grace à son index, on appelle la methode "draw_item" qui gere l'affichage.
En parametre, on trouve l'index du choix à afficher. Grace à cette index, on peut recuperer un Rect en utilisant la methode "item_rect" de Window_Selectable. Comme cette methode sert également à connaitre la taille et l'emplacement du curseur, nous avons toujours un affichage adapté au curseur. ( Enfin, tant qu'on utilise le Rect obtenu evidement !! ) Ca nous evitera bien des calculs ... Ensuite, on efface le Bitmap correspond au Rect, histoire de faire place net. ( Dans le script final du cours precedent, toutes nos actions se superposées les unes aux autres, mais ici, ça ne nous convient pas !! ) Grace à notre tableau et notre index, on recupere l'objet qui nous interesse. Comment ici il s'agit d'une String, je peux directement l'afficher. J'utilise le Rect pour etre bien positionné ( et centré pour faire plus joli ).
Enfin, comme j'ai associé une fenetre d'aide via ma scene, il faut que je renseigne l'affichage de celle ci. Rappel : la methode "update_help" est appellé par la methode "update" de Window_Selectable. Window_Help possede une methode "set_text" bien pratique qui permet d'afficher du texte de maniere simplifié et depuis une autre classe. On passe en parametre une String et l'alignement.
Il ne nous reste plus qu'a tester tout ça !!
Spoiler:
C'est magique, le curseur bouge parfaitement, la fenetre d'aide réagi aussitôt, vive Window_Selectable !! Gerer une fenetre, c'est bien pour commencer mais ça n'offre pas grand interet ... Voyons maintenant un exemple de scene plus complexe, avec plusieurs fenetres de choix !!
ASHKA
Voyageur Lv.10
Age : 42 Inscrit le : 04/12/2008 Messages : 383
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Mar 10 Fév 2009 - 18:08
Exemple de scene complexe :
On va créer une scene qui pourrait bien etre un sous-menu "Option". Nous avons besoin de trois fenetres : - Le liste des choix d'options a gauche ( Window_Command ). - En vis-à-vis à droite, les diferents reglages de chaques options ( Window_Selectable ). - En bas, une fenetre d'aide qui nous expliquera à quoi correspond les options et les choix. Pour nous simplifier la vie, nous allons utiliser un module pour regrouper les options, les reglages et les commentaires qui leurs seront associés.
Par contre, nous ne créeront qu'une structure vide. Les choix ne donneront lieu qu'a un Sound_Effect. Le but est ici de vous apprendre à utiliser les Window_Selectable.
Voila à quoi ça devrait ressembler à la fin :
Spoiler:
Evidement, avant d'en arriver là, on avons beaucoup de travail en perspective !! ( Enfin, pour vous, parce que moi, le script est déjà fait ... )
Premiere etape : Par quoi est-ce qu'on commence ?
Et bien, tout d'abord, on commence par reflechir !! Un script, même un simple, ça se pense bien avant de se coder !! Ca vous evitera bien de problemes de penser avant d'agir. Evidement, une scene comme celle là, c'est facilement modifiable. Mais c'est une habitude à prendre. Parce que, si au bout de 2000 lignes de code, vous vous rendez compte que vous n'arriverais à rien de cette façon, votre super CBS n'est pas pres de voir le jour ...
Vous avez de la chance, j'ai pensé pour vous ( donc, ce sera bien fait ... ). Il n'y a qu'une difficulté ici, c'est notre Window_Selectable ... Je me suis un peu laché, j'avoue.
def terminate dispose_menu_background @option.dispose @reglage.dispose @description.dispose end
def update update_menu_background if @reglage.active update_reglage elsif @option.active update_option end end
def update_option @option.update if Input.trigger?(Input::B) Sound.play_cancel $scene = Scene_Map.new elsif Input.trigger?(Input::C) Sound.play_decision @option.active = false @reglage.active = true @reglage.set_action(@option.index) end end
def update_reglage @reglage.update if Input.trigger?(Input::B) Sound.play_cancel @option.active = true @option.update_help(true) @reglage.active = false @reglage.index = -1 elsif Input.trigger?(Input::C) Sound.play_decision end end end
On utilise la methode "start" pour créer toutes nos fenetres, soit ici : - Window_Description, une fenetre toute simple qui herite de Window_Base ( celle du bas ). - Ma_Win_Cmd, une fenetre de choix qui hérite de Window_Command ( celle de gauche ). - Window_Reglage, une fenetre de choix egalement mais qui hérite de Window_Selectable ( celle de droite ).
Par defaut, les fenetres sont activent, c'est à dire que le curseur est actif. Pour eviter le probleme de gerer deux fenetres en même temps, on désactive @reglage, on l'a réactivera lorsqu"on aura choisi une option. Ensuite, on associe une fenetre d'aide ( ici de descritpion plutôt ) à nos fenetres de choix. Dans la methode de Window_Selectable qui appelle la mise à jour de la fenetre d'aide, il y a une condition "if self.active". Il n'y aura donc pas de probleme à réutiliser la même fenetre d'aide, nos deux fenetres de choix etant active à tour de role !!
Dans la methode "terminate", on n'oublie surtout pas de detruite nos fenetres !!
Comme on va gerer à tour de role deux fenetres differentes, il faut adapter l'update. On utilise le fait que la fenetre soit active comme condition de declenchement. Si @reglage est active, "update" appellera une methode spécifique qui gerera les actions propres à la fenetre active. Et même chose avec @option, elle aura elle aussi sa propre methode pour gerer les actions. Rappellez vous bien de ça, c'est fondzmentale pour pouvoir créer des scenes complexes. Chaque methode à sa fonction, il faut mieux eviter de créer des methodes à rallongue, avec une condition en "fermant" une grande partie.
Chaque methode commence par appeller la methode "update" de la fenetre active. Rappellez vous que c'est cette methode qui gere les deplacements du curseur, il serait dommage de l'oublier ... En cas de choix d'une option, on passe d'une fenetre à l'autre en modifiant l'attribut "active" des fenetres. Dans "update_reglage", en cas de retour, on fixe l'index de la fenetre à -1 pour le rendre invisible. La methode "set_action" sert à passer à la fenetre @reglage le choix effectué, ce qui influera sur la position du curseur.
Habituellement, les Window_Command n'ont pas de fenetre d'aide. J'ai donc du en rajouter une, ce qui explique l'utilisation d'une classe spécifique héritant de Window_Command. Cette classe est vraiment reduite au maximum, la voici :
Code:
class Ma_Win_Cmd < Window_Command def update_help(force = false) if force or @test_index != self.index tab = Test::Desc_Option[self.index] @help_window.refresh(tab) @test_index = self.index end end end
Window_Command hérite de Window_Selectable, toute la structure permettant d'utiliser une fenetre d'aide est déjà là, mais elle n'etait pas utilisé !! J'ai juste eu à definir ma methode "update_help", l'heritage faisant le reste. ( Encore une fois, je me repete, mais laissons les parents tout faire à notre place !! ) Alors, si jamais le curseur change de position, on mets à jour la fenetre d'aide. Inutile d'utiliser le "refresh" en permanence, rapellez vous, economisons nos forces !! J'ai aussi integré une systeme permettant de forcer la mise à jour, voila pourquoi : Lorsque la deuxieme fenetre devient active, le curseur de la premiere reste en place mais l'affichage de la fenetre d'aide change. En cas de retour, la fenetre de choix d'option redevient active, il faut donc que l'affichage de la fenetre d'aide revienne adapté. Mais le probleme est que le curseur n'a pas bougé ... donc ma condition empechera la mise à jour ... Plutôt que d'appeller la methode "refresh" en permanence, cette astuce de forcer la mise à jour est plus adapté !! Par defaut ( enfin, sans parametre ), le passage en force est desactivé. Oui, sans modification, Window_Selectable appelle la methode "update_help", sans parametre !!
ASHKA
Voyageur Lv.10
Age : 42 Inscrit le : 04/12/2008 Messages : 383
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Mar 10 Fév 2009 - 18:14
Depuis le temps qu'on parle d'elle, il faut que je vous la presente ... Voici notre fenetre de description :
Code:
class Window_Description < Window_Base def initialize h = (4 * 24) + 32 + 15 super(0, 416-h, 544, h) refresh([]) end def refresh(tab) if tab != [] self.contents.clear y = 0 for line in tab self.contents.draw_text(0, y, 544-32, 24, line, 1) y += 24 end end end end
Une Window tout ce qu'il y a de plus classique ... sans fioriture. J'aurais pu mettre de la couleur, un trait pour separer le titre et la description, mais non ... la flemme !! ( Non, en fait, si vous voulez, faite le, moi, je sais déjà comment faire ... ) Comme cette fenetre doit servir dans deux cas differents ( Option et Reglage ), il a fallu trouver un moyen de rendre ça simple. Evidement, j'aurais pu passer un parametre indiquant quelle fenetre est active, quelle est la postion du curseur et en fonction de ça, avec une suite de condition longue comme une journée sans pain, afficher ce qui correspond. Mais, je suis un gros paresseux ... J'ai donc essayé d'automatiser au maximum. En fonction de l'index, la methode "update_help" envoi en parametre un tableau. Une petite boucle ( for ) fait le reste. Tout est donc stocké dans un module. Plutôt que de mettre toutes mes String directement dans le script, j'utilise un module, c'est nettement plus simple. Voici ce module ( trop long pour entrer dans un message ) :
Fichier txt ...
On y trouve la liste des options, la liste des reglages, et les descriptions correspondant à tous les choix possible. Vive les Hash !! Bon, chaqu'un son truc, moi, j'aime bien les Hash, les Hash, c'est cool. ( Le permier qui tente un jeu d emot avec mon pseudo, je le ........ ) Pour "Desc_Reglage", il faut donc deux clés pour acceder au tableau. Ces clés seront donc le choix de la fenetre d'option et la position du curseur dans la fenetre de reglage.
La fenetre de reglage ? Tiens, c'est parfait ça comme enchainement, ok, allons y voici la fenetre de reglage :
Spoiler:
Code:
class Window_Reglage < Window_Selectable def initialize h = (10 * 24) + 32 super(130, 0, 544-130, h) @action = 0 refresh end
def set_action(num) tab = Test::Liste_Reglage[num] @column_max = @item_max = tab.size @action = num @index = 0 case @action when 2,6,8 @spacing = 0 else @spacing = 32 end update_help(true) end
def refresh @data = [] for x in 0...Test::Liste_Reglage.keys.size @data.push(Test::Liste_Reglage[x]) end create_contents for i in 0...@data.size draw_item(i) end end
def item_rect(index, rang = @action) rect = Rect.new(0, 0, 0, 0) rect.width = (contents.width + @spacing) / @column_max - @spacing rect.height = WLH rect.x = index % @column_max * (rect.width + @spacing) rect.y = index / @column_max * WLH + (rang * 24) return rect end
def draw_item(index) tab = @data[index] @column_max = @item_max = tab.size case index when 2,6,8 @spacing = 0 else @spacing = 32 end for x in 0...tab.size item = tab[x] rect = item_rect(x, index) self.contents.clear_rect(rect) if item != nil rect.width -= 4 self.contents.draw_text(rect, item, 1) end end end
def update_help(force = false) if force or @test_index != @index tab = Test::Desc_Reglage[@action][@index] @help_window.refresh(tab) @test_index = @index end end end
On va diviser l'etude en deux axes : - L'affichage. - La gestion du curseur.
Tout d'abord, regardons comment s'effectue l'affichage. L'initialize n'offre pas grand interet, passons de suite à la methode "refresh". Notre tableau @data est rempli à partir de notre liste, celle qui se trouve dans le module. Ici, le tableau ne contient ni des String, ni des objets RPG::Item mais des Array. Chaque Array correspond à une option. L'affichage est donc particulier, je ne peux pas afficher le tableau tel quel, ça ne donnerais rien de bien ... D'ailleurs, on remarquera que je n'ai pas encore donner de valeur à @column_max ( donc c'est 1, la valeur par defaut ) ou à @item_max ( même chose, 1 ). Pourtant, je passe directement à la methode "draw_item", celle qui habituellement gere l'affichage des objets "choix".
Methode "draw_item" : Grace à l'index, je recupere mon tableau contenant les choix. Il ne me reste plus qu'a les afficher. Comme le nombre de choix est different selon les options, ce n'est que maintenant que je fixe le nombre de colonne et d'objet max. J'ajuste egalement l'espace ( ici, un case pour reduire l'espace lorsqu'il y a beaucoup de choix à afficher ). J'ai fixé le nombre de colonne, la methode "item_rect" va donc calculer ele même la position de chaque option. Ici, je rajoute un parametre, "index", c'est à dire l'option choisi. Si on regarde la redefinition de "item_rect", on constate que ça me sera utile pour afficher chaque option sur une ligne differente. C'est aussi simple que ça, tout est automatique, il suffit de s'adapter !!
Passons donc à la gestion du curseur. Toutes les modifications passent par la methode "set_action", appellé au moment de choisir une option. En fonction de ce choix, j'ajuste les valeurs de @column_max, @item_max et @spacing. Comment nous l'avons vu pour l'affichage, ça suffira à créer le curseur adapté. Le curseur est crée par la methode "item_rect" qui est appellé par la methode "update_cursor" de Window_Selectable. Je n'allais pas redefinir cette methode juste pour rajouter un parametre à "item_rect". ( Souvenez vous, comme pour l'affichage, l'index indiquant sur quelle ligne se placer ). Cette fois aussi, j'utilise le principe des valeurs par defaut s'il n'y a pas de parametres. Cette valeur sera celle de la variable @action. Tout comme il l'a fait pour l'affichage, "item_rect" nous fournira un Rect adapté pour le curseur.
La derniere chose à faire, c'est mettre en place la mise à jour de la fenetre de description. C'est quasiment la même methode que pour Ma_Win_Cmd, avec le systeme pour forcer la mise à jour. Grace aux variables @action et @index, j'ai les deux clés qui me permettent de recuperer le tableau à passer en parametre.
Voila, vous savez tout ce qu'il y a à savoir sur les Window_Selectable. Vous allez pouvoir créer tous les menus que vous voulez maintenant !! Comme je vous l'ai dis au debut du cours precedent, les menus sont une part importante dans les RPG. Et au niveau script, c'est ce qu'il y a de plus simple à créer. Ce qui nous donne de long et complexe cours en perspective !!
Etudiez le cours avec attention, Hikari postera les exercices à faire !!
ASHKA
Dernière édition par ASHKA le Mar 27 Oct 2009 - 8:19, édité 1 fois
MirainoHikari
Ex-Admin-Script
Age : 42 Inscrit le : 26/05/2008 Messages : 2360
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Mer 11 Fév 2009 - 13:45
Wow... ASHKA, tu t'es "lâché lousse"... Bon bon bon... Maintenant, faire un exercices pour pratiquer tous ces beaux apprentis...
1) Comment est calculer la taille de l'index (4pts) a) dans une Windows_Command? b) dans une Windows_Selectable?
2) Quelle variable permet de savoir où est rendu le curseur dans une Windows_Selectable? (2pts)
3) Lorsque nous avons une interface multi-fenêtre, comment est-il préférable de faire la gestion d'affichage de chacune d'elles? (4pts)
4) Au cours 5 et au cours 6, ASHKA a parlé d'une variable qui rendait active et une qui rendait visible les fenêtres. Faites une fenêtre de sélection qui permettra d'afficher ou de masquer la fenêtre d'aide. (4pts)
5) Voyons voir si vous avez bien intégré les concepts. SANS UTILISER DE WINDOWS_COMMAND, vous allez faire une interface permettant de faire une sélection combiné. Vous ferez une première fenêtre de sélection qui vous permettra de choisir parmis les 26 lettres de l'alphabet (A-Z) puis, lorsque la lettre est choisi, ferai la sélection des chiffre (0-9). Chaque fois que vous sélectionnez une lettre, le curseur de la fenêtre des chiffres retourne à 0. Lorsque vous sélectionnez vous lettre et vos chiffre, votre fenêtre d'aide affichera la combinaison. Exemple, « S7 » ou «S - 7». (6pts)
Bonne chance à tous.
Dernière édition par MirainoHikari le Jeu 5 Mar 2009 - 15:04, édité 1 fois
yamazaki
Illusionniste Lv.12
Age : 34 Inscrit le : 27/12/2008 Messages : 757
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Jeu 5 Mar 2009 - 14:35
salut pouvez vous me dire comment on fait pour changer l'image du rectangle de sélection et le remplacer par un curseur?
Invité
Invité
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Jeu 5 Mar 2009 - 14:38
ASHKA m'avait donné ce code une fois
Code:
class Window_MenuStatus< Window_Selectable def initialize(x,y) super(x,y,544,275) @column_max = 2 @spacing = 20 self.active = false self.index = -1 @curseur = Sprite.new @curseur.bitmap = Cache.picture("cursor") @curseur.z = 100 @curseur.visible = self.index != -1 refresh end def dispose @curseur.bitmap.dispose @curseur.dispose super end def update_cursor return if @curseur == nil @curseur.visible = index != -1 rect = item_rect(index) @curseur.x = rect.x + (rect.width / 2) - (@curseur.bitmap.width / 2) @curseur.y = rect.y + (@curseur.bitmap.height / 2) + 91 end end
Si ça peut aider.
MirainoHikari
Ex-Admin-Script
Age : 42 Inscrit le : 26/05/2008 Messages : 2360
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Jeu 5 Mar 2009 - 15:05
Je viens de publier les exercices. Ils sont plus difficile cette fois, mais vous avez passer au travers des 5 premiers cours et de l'examen, c'est normal que le niveau augmente un peu.
Invité
Invité
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Jeu 5 Mar 2009 - 15:21
Petite question prof, est ce que l'examen doit être fait avant ces exercices ou est ce qu'on peut déjà travailler sur ces exercices?
MirainoHikari
Ex-Admin-Script
Age : 42 Inscrit le : 26/05/2008 Messages : 2360
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Jeu 5 Mar 2009 - 15:25
Non, les exercices de ce cours peuvent être fait avant l'examen, mais il est obligatoire cependant d'avoir remis les exercices du cours 5 avant de soumettre ses réponse pour l'examen ou le cours 6. D'ailleur, travailler le cours 6 est une révission intéressante pour l'examen, donc je vous le suggère. Cependant, n'oubliez pas de répondre à l'examen un jour. Le site web ne restera pas ouvert indéfiniment. Un jour, je lui trouverai un serveur permanent.
La Meche
Flibustier Lv.21
Age : 30 Inscrit le : 24/05/2008 Messages : 3234
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Dim 15 Mar 2009 - 13:44
J'ai une petite question pour ce qui est de la syntaxe : Est ce que l'on peut mettre des accents ou des "ç" pour les nom de variables, module, class etc... sans qu'il n'y est d'erreur ? (je viens de tester, pour l'instant sa marche mais je ne sais si sur longue durée c'est bien)
berka
Maire Lv.9
Age : 34 Inscrit le : 15/10/2008 Messages : 351
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Dim 15 Mar 2009 - 14:23
il faut bannir tous les caractères spéciaux des noms de méthodes: il y a en ruby des conventions de nommages très strictes. Ton interpréteur s'en fout la plupart du temps, mais c'est pour la forme:
Code:
MA_CONSTANTE || MaConstante $ma_variable def meth_booleen? #renvoie true ou false def destruct! #change self: methode destructrice class Chose_Test || class ChoseTest
normalement, après chaque opérateur, on devrait mettre un espace: a = b + (4 ** 2) mais je trouve que ca prend beaucoup trop de place
Ca sert a se repérer ! Et à éviter les pertes de caractères sur des sites etrangers (utf8/unicode...)
berka
La Meche
Flibustier Lv.21
Age : 30 Inscrit le : 24/05/2008 Messages : 3234
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Dim 15 Mar 2009 - 15:16
Donc on peut le faire ? Ou faut suivre le "lois" qui dit de pas en mettre ?
Aussi comment sais-t-on quel caractétre n'est pas lu par tel site étranger (genre utf8/unicode...)
berka
Maire Lv.9
Age : 34 Inscrit le : 15/10/2008 Messages : 351
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Dim 15 Mar 2009 - 17:58
ce sont des lois: elles sont rendues obligatoires pour simplifier la vie des codeurs, mais elles ne font pas planter ruby...(enfin si tu mets ["#&~... dans ton nom...)
le mieux c'est de les suivre... Et je ne vois pas tellement ce qui t'empeche de ne pas les suivre ^^
berka
MirainoHikari
Ex-Admin-Script
Age : 42 Inscrit le : 26/05/2008 Messages : 2360
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 16 Mar 2009 - 12:00
D'ailleur, j'en ai fait mention dans un cours précédent La Meche... Même si VX ne semble pas trop s'en faire avec les accents/caractère spéciaux, il est préférable de rester en "english style". Donc au lieu d'écrire Français_Éloquent, prends l'habitude d'écrire Francais_Eloquent. C'est peut-être pas dans un beau français sans coquille, mais tu risques moins d'avoir des problème de compatibilité le jour ou tu changeras d'interpréteur. VX supporte bien les UNICODE, mais si tu y réfléchies un peu, ça été développé par des japonais pour supporter leur caractères (tous unicode), donc on comprend pourquoi ça ne le dérange pas trop. Mais prends un interpréteur autre (car je sais que tu voulais te lancé en ruby pur) tu risques fort de tomber sur un interpréteur US qui n'a que le ASCII de base (même pas étendu). Si c'est le cas, ben tes accents vont être interprétés comme des caractère de flux ou des caractères inconnus. Dans un cas comme dans l'autre, tu risques d'avoir des problèmes. Donc à bannir de tes noms de variables. Pour une valeur de chaîne (string) c'est ok (ex. ma_string = "Je suis Français") Entre les guillemets, c'est correct, mais pas dans le nommage. Donc, à bon entendeur...
Dernière édition par MirainoHikari le Lun 16 Mar 2009 - 15:41, édité 1 fois
La Meche
Flibustier Lv.21
Age : 30 Inscrit le : 24/05/2008 Messages : 3234
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 16 Mar 2009 - 14:58
Bon bah ok... En fait c'est juste que je dois écrire hamecon au lieux de hameçon et j'aime pas ^^' C'est tout ! (Ainsi que Pecher au lieux de Pêcher) Bref, merci sur ces explications ^^
MirainoHikari
Ex-Admin-Script
Age : 42 Inscrit le : 26/05/2008 Messages : 2360
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 16 Mar 2009 - 15:43
Ton autre possibilité est de coder en anglais . Donc au lieu de hameçon et pêcher, écrit lure et fishing comme nom de variable...
La Meche
Flibustier Lv.21
Age : 30 Inscrit le : 24/05/2008 Messages : 3234
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 16 Mar 2009 - 16:16
ah ouais ! Pas con bête ça ! Merci beaucoup !
Fallait chercher loin dit-moi ma petite mechouille ... !
ASHKA
Voyageur Lv.10
Age : 42 Inscrit le : 04/12/2008 Messages : 383
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Mar 27 Oct 2009 - 8:22
J'ai re-uploadé le .txt du module.
Fichier module
Kouett
Mage Lv.11
Age : 26 Inscrit le : 22/08/2010 Messages : 521
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 20 Sep 2010 - 18:25
Ben, Je tiens a vous Féliciter. C'est Pas facile de Créez Des Script
Blockade
Ex-Admin Cruelle
Age : 32 Inscrit le : 03/07/2008 Messages : 2441
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe. Lun 20 Sep 2010 - 19:25
Ouais cool. Mais la c'est du nécropost + flood donc désolée mais c'est l'avertissement. Merci de faire attention à l'avenir
Contenu sponsorisé
Sujet: Re: Cours # 6 : Window_Selectable et scene complexe.