Night.png);">
Apprendre


Vous êtes
nouveau sur
Oniromancie?

Visite guidée
du site


Découvrir
RPG Maker

RM 95
RM 2000/2003
RM XP
RM VX/VX Ace
RM MV/MZ

Apprendre
RPG Maker

Tutoriels
Guides
Making-of

Dans le
Forum

Section Entraide

Sorties: Star Trek: Glorious Wolf - (...) / Sorties: Dread Mac Farlane - episode 3 / News: Plein d'images cools créées par (...) / Sorties: Star Trek: Glorious Wolf - (...) / Jeux: Final Fantasy 2.0 / Chat

Bienvenue
visiteur !




publicité RPG Maker!

Statistiques

Liste des
membres


Contact

Mentions légales

253 connectés actuellement

29185649 visiteurs
depuis l'ouverture

5914 visiteurs
aujourd'hui



Barre de séparation

Partenaires

Indiexpo

Akademiya RPG Maker

Blog Alioune Fall

Fairy Tail Constellations

Leo-Games

Eclipso

Le Comptoir Du clickeur

Offgame

RPG Maker VX

Tous nos partenaires

Devenir
partenaire



Commandes rotatives

Vous en avez marre que le rectangle de sélection se déplace à chaque fois que vous appuyez sur "haut-bas" ? Si comme moi vous voulez voir votre menu tourner et se dérouler de haut en bas lorsque vous montez en descendez grâce aux touches directionnelles,

Script pour RPG Maker XP
Ecrit par TLN
Publié par TLN (lui envoyer un message privé)
Signaler un script cassé

❤ 0

Bonjour tout le monde !
Voici un vrai script cette fois, qui en aidera je l'espère plus d'un.

Il s'agit d'obtenir un effet "rouleau" à la place d'une selection classique, comme sur cet exemple :
image

Outre le côté sympathique du script et le fait de créer un effet de rotation pour les différentes options d’un choix, ce tutorial a comme buts :
_ Une initiation au système de déplacement d’objet sous rmXP avec des données variables ;
_ Un sur le cercle, les coordonnées polaires, et les coordonnées d'un point d’un cercle (partie barbante, c'pour ceux qui z'y comprennent rien mais qui veulent lire quand même) ;
_ Une compréhension de certaines fonctions de ruby et de l’interaction entre les méthodes et les variables.

*'Tention, z'allez en apprendre des trucs dans ce tuto image*

NOTE : Pour les fénéants, ceux qui connaissent déjà tout ça ou tout simplement ceux qui on juste envie d'installer le script, ne lire que les parties I) et II).

I) Installation :

Comment installer ce script chez vous ? C’est très simple, copiez simplement le script ci-dessous dans un nouveau script que vous pourrez appeler par exemple "Window_Command_Rotation" et placez-le entre "Main" et "Window_Base" (par exemple à la fin de la série des "Window".

Portion de code : Tout sélectionner

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#==============================================================================
# Window_Command_Rotation
#------------------------------------------------------------------------------
#==============================================================================
class Window_Command_Rotation < Window_Base
  #--------------------------------------------------------------------------
  attr_reader   :index
  attr_reader   :help_window
  #--------------------------------------------------------------------------
  def initialize(width, commands, vitesse = 10, largeur=24, rayon=nil)
    super(0, 0, width, commands.size * 32 + 32)
    @n = commands.size
    if rayon == nil
      @r = @n*8 + 8
    else
      @r = rayon
    end
    @ell = largeur
    @dist = Math::PI * 2/@n
    @x = []
    @y = []
    @angle = []
    @item_disabled = []
    for i in 0...@n
      @x[i] = @ell * -Math.cos(@dist*i)  + @ell + 4
      @y[i] = @r * Math.sin(@dist*i) + @r + 8
      @angle[i] = @dist*i
    end
    @y_rect = @y[0]
    @column_max = 1
    @index = -1
    @item_max = commands.size
    @commands = commands
    @vitesse = vitesse
    @move = 0
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    self.contents.font.name = $fontface
    self.contents.font.size = $fontsize
    refresh
    self.index = 0
  end
# ------------------------------------
  def refresh
    self.contents.clear
    for i in 0...@item_max
      draw_item(i, color_item(@angle[i], i))
    end
  end
# ------------------------------------
  def draw_item(index, color)
    self.contents.font.color = color
    rect = Rect.new(@x[index], @y[index], self.contents.width - 8, 32)
    self.contents.draw_text(rect, @commands[index])
  end
# ------------------------------------
  def disable_item(index)
    @item_disabled[index] = true
    refresh
  end
# ------------------------------------
  def move_item(sens, vitesse = @vitesse)
    d = vitesse
    @move += sens
    loop do
      self.contents.clear
      for i in 0...@n
        @x[i] = @ell * -Math.cos((@angle[i]*(d-1) + @dist*(i+@move) )/d)  + @ell + 4
        @y[i] = @r * Math.sin( (@angle[i]*(d-1) + @dist*(i+@move) )/d) + @r + 8
        @angle[i] = (@angle[i]*(d-1) + @dist*(i+@move) )/d
        draw_item(i, color_item(@angle[i], i))
      end
      Graphics.update
      d -=1
      if d == 0
        break
      end
    end
  end
# ------------------------------------
  def color_item(angle, i)    
    if @item_disabled[i] == true
      transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI
    else
      transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI + 50
    end
    return Color.new(255, 255, 255, transparence)
  end
# ------------------------------------
  def index=(index)
    @index = index
    if self.active and @help_window != nil
      update_help
    end
    update_cursor_rect
  end
  #--------------------------------------------------------------------------
  def row_max
    return (@item_max + @column_max - 1) / @column_max
  end
  #--------------------------------------------------------------------------
  def top_row
    return self.oy / 32
  end
  #--------------------------------------------------------------------------
  def top_row=(row)
    if row < 0
      row = 0
    end
    if row > row_max - 1
      row = row_max - 1
    end
    self.oy = row * 32
  end
  #--------------------------------------------------------------------------
  def page_row_max
    return (self.height - 32) / 32
  end
  #--------------------------------------------------------------------------
  def page_item_max
    return page_row_max * @column_max
  end
  #--------------------------------------------------------------------------
  def help_window=(help_window)
    @help_window = help_window
    if self.active and @help_window != nil
      update_help
    end
  end
  #--------------------------------------------------------------------------
  def update_cursor_rect
    if @index < 0
      self.cursor_rect.empty
      return
    end
    row = @index / @column_max
    if row < self.top_row
      self.top_row = row
    end
    if row > self.top_row + (self.page_row_max - 1)
      self.top_row = row - (self.page_row_max - 1)
    end
    cursor_width = self.width / @column_max - 32 - 2*@ell
    x = @index % @column_max * (cursor_width + 32)
    self.cursor_rect.set(x, @y_rect, cursor_width, 32)
  end
  #--------------------------------------------------------------------------
  def update
    super
    if self.active and @item_max > 0 and @index >= 0
      if Input.repeat?(Input::DOWN)
        if (@column_max == 1 and Input.trigger?(Input::DOWN)) or
           @index < @item_max - @column_max
          $game_system.se_play($data_system.cursor_se)
          @index = (@index + @column_max) % @item_max
          move_item(-1)
        end
      end
      if Input.repeat?(Input::UP)
        if (@column_max == 1 and Input.trigger?(Input::UP)) or
           @index >= @column_max
          $game_system.se_play($data_system.cursor_se)
          @index = (@index - @column_max + @item_max) % @item_max
          move_item(1)
        end
      end
      if Input.repeat?(Input::RIGHT)
        if @column_max >= 2 and @index < @item_max - 1
          $game_system.se_play($data_system.cursor_se)
          @index += 1
        end
      end
      if Input.repeat?(Input::LEFT)
        if @column_max >= 2 and @index > 0
          $game_system.se_play($data_system.cursor_se)
          @index -= 1
        end
      end
      if Input.repeat?(Input::R)
        if self.top_row + (self.page_row_max - 1) < (self.row_max - 1)
          $game_system.se_play($data_system.cursor_se)
          @index = [@index + self.page_item_max, @item_max - 1].min
          self.top_row += self.page_row_max
        end
      end
      if Input.repeat?(Input::L)
        if self.top_row > 0
          $game_system.se_play($data_system.cursor_se)
          @index = [@index - self.page_item_max, 0].max
          self.top_row -= self.page_row_max
        end
      end
    end
    if self.active and @help_window != nil
      update_help
    end
    update_cursor_rect
  end
end




II) Manuel d'utilisation.

C'est assez simple, au lieu de créer une fenêtre de commande normale, avec la ligne :

Portion de code : Tout sélectionner

1
@command = Window_Command.new(160, ["Choix 1", "Choix 2", "Choix 3, "Choix 4"]


Mettez ceci :

Portion de code : Tout sélectionner

1
@command = Window_Command_Rotation.new(160, ["Choix 1", "Choix 2", "Choix 3, "Choix 4"])



À noter cependant que votre ligne peut se présenter sous cette forme :

Portion de code : Tout sélectionner

1
@commands = Window_Command.new(160, [s1, s2, s3, s4]


Et ceci précédant la même ligne :

Portion de code : Tout sélectionner

1
2
3
4
s1 = "Choix 1"
s2 = "Choix 2"
s3 = "Choix 3"
s4 = "Choix 4"



Ce qui revient au même puisque l'on assigne à quatre variable des chaînes de caractères (grâce aux guillemets), et l'on entre ces variables dans le tableau correspondant aux choix à la ligne qui crée un nouvel objet "Window_Command" et l'assigne à la variable locale à une classe "@command". Ca sert juste à "alléger" le script en créant une ligne moins lourde d'information et donc plus facile à comprendre.

Mis part ces deux valeurs (la première, 160, correspondant à la largeur du rectangle de sélection, plus c'est petit et plus vos choix risquent d'être coupés par la fin du rectangle à droite ; la deuxième, "[...]" est une matrice de valeur, ce sont les différents choix qui vont être affichés (il ne doit donc pas y figurer de nombre ou de "true", "false" et "nil" et les caractères -si vous introduisez directement les caractères et non les variables leurs correspondant- doivent être introduit entre guillemets sans quoi ils ne seront pas considérés comme des chaînes de caractère mais comme des variables à part entières)), vous pouvez entrer trois autres paramètres facultatifs :
_ La vitesse de rotation, qui est de 10 par défaut (je crois que ce sont des demi-millisecondes).
_ La largeur de l'ellipse selon laquelle seront affichés vos commandes, 24 par défaut. Il s'agit du petit rayon (ou grand ça dépendra) de l'ellipse, plus vous entrez une grande valeur plus vos choix auront l'air aplatis et allongés horizontalement (par dans le sens dilatés, mais leurs positions seront plus élargies).
_ Enfin, vous pouvez toujours entrer le rayon, ou la hauteur de l'ellipse, qui est calculé par défaut selon le nombre d'éléments du tableau de choix si la variable correspond à "nil" (c'est-à-dire à rien pour rmXP).

Attention cependant à ne pas entrer une valeur à la suite que vous voulez être la largeur de l'ellipse sans entrer avant sa vitesse de rotation, car rmXP n'aura aucun moyen de savoir s'il s'agira de la vitesse ou de la largeur, il prendra donc cette valeur pour celle de la vitesse (celle qui doit être inscrite en troisième donc, avant la largeur et le rayon, mais après la largeur du rectangle et le tableau de choix).

III) Compréhension.

1) Approche théorique du problème - Coordonnées polaires et Cercles inside.

image

Alors pour comment à résonner sur notre problème, qu'avons-nous à faire ?
_ L'on veut afficher un nombre de point variable à égale distance les uns des autres sur une ellipse de petit et de grand rayons variables.
_ L'on ne peut afficher ces points que par leurs coordonnées cartésiennes (x et y) et non polaires.

Comment faire ?
1- Calculer la circonférence de l'ellipse, la diviser par le nombre de point et placer ensuite ces derniers à égales distances dessus.
2- Autre solution.

Alors la première solution, c'est barbare, long et chiant à faire. Et aussi parce que la circonférence d'une ellipse se calcule à partir d'intégrales, il n'est pas question d'utiliser cette méthode sous rmXP. (Et, entre nous soit dit, même sur papier, c'est bien prise de tête alors qu'on peut faire plus simple).

Il nous reste donc à trouver une autre solution, mais laquelle ?

On souhaite que les coordonnées x soient dilatées par rapport à y, d'après le 1er dessins, si l'on calcule x avec un premier rayon r1 et y avec un deuxième rayon r2 on donnera cet effet "aplati" tant recherché.


Ensuite cherchons un peu de quelles informations l'on dispose au début : le nombre d'objet, les deux rayons (dont le rayon r2 donné en fonction du nombre d'objet sauf s'il est imposé, voir explication plus bas), et la vitesse.
Bien, passons à l'équation qui calculera la distance entre les points.
Pour faire simple on va calculer l'angle séparant chaque point de façon à ce qu'il soit le même pour tous les points : a = 2*π/@nombre_de_point. On divise équitablement l'angle maximum (2π, ou 360°) en fonction du nombre de point.

Passons au calcul des coordonnées x et y : x = r1 * -cos(a*i) + r1 + 4
On ajoute r1 car le référentiel utilisé pour placer les points dans rm part du point haut gauche, on "centre" donc notre ellipse, quel que soit son rayon r1, et on y ajoute 4 pour le "décoller" un peu (car il faut penser qu'il y a aussi une bordure). On multiplie cos par -1 de sorte de tourner à l'envers (dans le sens des aiguilles d'une montre en partant de la gauche).
y = r2 * sin(a*i) + r2 + 8
Idem qu'avec x ... (à noter cependant que l'on ne multiplie pas le sinus par -1 car l'axe des y pour afficher une image en ruby est déjà dans le sens haut vers bas)

2) Approche théorique du mouvement d'objets dans la programmation en ruby d'rmXP.

L'équation de mouvement en ruby est assez simple, elle se présente sous cette forme :
@x = (@x * (d - 1) + @target_x) / d
Où @x équivaut à la valeur de la variable que vous voulez changer, et @target_x la valeur finale de votre variable. Notez que d est la variable de temps, elle doit diminuer d'une unité à chaque boucle pour donner l'impression de mouvement et ne doit pas être négative ni égale à 0 (sans quoi la division ne peut s'effectuer).
Ainsi l'on peut constater que lorsque d est grand, @target_x n'influe presque pas sur la valeur finale de @x, mais si d est égal à 1, il ne reste plus que @target_x (puisque @x a été multiplié par 0) et @x va prendre la valeur de @target_x (qui sera divisé par 1). @x change à chaque fois, de même que la valeur intermédiaire entre @x et @target_x varie selon d ...

Bref pour résumer comment ça marche, on a une valeur à changer, une valeur finale et on utilise cette équation.
Comme dans notre cas on ne veut pas directement changer les x et le y de chacun, on modifie l'angle, on aura donc ceci :
x = r1 * -cos((angle*i*(d-1) + a*(i±1))/d) + r1 + 4
y = r2 * sin((angle *i*(d-1) + a*(i±1))/d) + r2 + 8
angle = (angle *i*(d-1) + a*(i±1))/d

Où "angle" est l'angle du point i à un instant donné d. Ainsi comme il s'agit de l'angle que l'on veut modifier à chaque fois on entre dans l'équation "angle = ..." et notre angle variera.
Ensuite pourquoi ai-je mis ±1 ? Tout simplement car cela dépendra du sens de variation, la valeur finale sera égale aux coordonnées du point i±1 et ce en modifiant l'angle à chaque fois.
Voilà bien sûr en ruby on va scripter ça d'une façon un peu différente mais qui dans le fond gardera le même principe.

Et c'est fini pour l'approche théorique passons à l'explication linéaire :

3) Explication linéaire de quelques fonctions utilisées pour ce script.

Tout d'abord il faut savoir que j'ai regroupé les script Window_Command et Window_Selectable afin de pouvoir modifier des choses dans les deux scripts et poster ça sans trop modifier le jeu sur lequel on va l'utiliser.

Portion de code : Tout sélectionner

1
class Window_Command_Rotation < Window_Base


On commence ... on crée une nouvelle classe, un nouveau type d'objet si vous préférez, on la place en dessous de window_base de sorte de pouvoir profiter des méthodes déjà définies dans ce script. Le logiciel va alors pouvoir lancer la méthode d'initialisation (pour les variables et companie).

Portion de code : Tout sélectionner

1
2
3
4
5
  attr_reader   :index
  attr_reader   :help_window/code]
Alors alors ... ça faisait parti du script "Window_Selectable" à l'origine.
Ca sert à pouvoir lire la variable locale portant le nom spécifié (ici respectivement "index" et "help_window") depuis un autre script par exemple. Ainsi, si l'on crée un objet nommé :
[code]@command_window = Window_Command_Rotation.new(300, [s1, s2, s3, s4])


L'on pourra avoir accès à la variable "@index" (puisqu'il s'agit d'une variable locale, ça commence donc par "@"), en tapant :

Portion de code : Tout sélectionner

1
@command_window.index


Très util pour connaitre l'index de notre commande ; on ne peut cependant que lire cette variable (normal, c'est indiqué "attr_reader" devant)
Du coup la commande :

Portion de code : Tout sélectionner

1
if @command_window.index == 2


Vérifiera si l'index est égal à deux, mais vous ne pourrez pas le changer en mettant par exemple :

Portion de code : Tout sélectionner

1
@command_window.index = 3


Dans votre code. Pour cela il vous faudra remplacer le "attr_reader" dans votre en-tête de script par :

Portion de code : Tout sélectionner

1
  attr_accessor :variable


De même avec "attr_writer" je suppose que vous devinez que ça ne permet que d'écrire sur ladite variable.

Portion de code : Tout sélectionner

1
2
  def initialize(width, commands, vitesse = 10, largeur=24, rayon=nil)
    super(0, 0, width, commands.size * 32 + 32)


La méthode initialize qui, dès qu'une variable est créée comme étant un nouvel objet de cette classe, va être executée. Lorsque par le biais de cette commande :

Portion de code : Tout sélectionner

1
@variable = Objet.new


On définie un nouvel objet, si l'on veut faire passer des valeurs pour qu'elles soit utilisées dans la classe "Objet" (genre ici le nombre de commandes de la fenêtre, sa largeur, etc.) on doit ajouter ceci :

Portion de code : Tout sélectionner

1
@variable = Objet.new(argument)


Où "argument" est une variable, c'est-à-dire une chaîne de caractère, un nombre, un "true" (vrai), "false" (faux) ou "nil"(rien), ou encore un tableau ("[]") et qui va être lue par cette méthode initialize :

Portion de code : Tout sélectionner

1
  def initialize(argument = "valeur_par_défaut" )


À noter que le "= "valeur_par_défaut"" est facultatif et que si vous le mettez, vous ne serez pas obligé d'envoyer une valeur lorsque vous créerez votre objet (c'est-à-dire concrètement que vous ne serez pas obligé d'imposer une valeur à "argument" car la variable aura une valeur par défaut que le logiciel utilisera si vous n'en imposez pas). De plus le "argument" doit être une variable locale (donc pas de @, @@, ni de $ devant votre variable).
Sans cela votre script boguera.

Ensuite on appelle le script Window_Base sous lequel est placée notre classe pour l'initialiser grâce à la commande "super(machin, machin)" (en fait ça appelle plus précisément la méthode "initialize" du script "Window_Base" mais c'est un détail pour l'instant).

Portion de code : Tout sélectionner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@n = commands.size
    if rayon == nil
      @r = @n*8 + 8
    else
      @r = rayon
    end
    @ell = largeur
    @dist = Math::PI * 2/@n
    @x = []
    @y = []
    @angle = []
    @item_disabled = []
    for i in 0...@n
      @x[i] = @ell * -Math.cos(@dist*i)  + @ell + 4
      @y[i] = @r * Math.sin(@dist*i) + @r + 8
      @angle[i] = @dist*i
    end
    @y_rect = @y[0]



Là on initialise certaines variables, telle @n qui sera égale au nombre d'option, @r qui sera égale au nombre d'option multiplié par 8 plus 8 si aucun rayon n'a été précisé, la largeur qui a une valeur par défaut de 24 pixels, la distance angulaire séparant chaque option (2*π/@n). Ensuite on crée un tableau, ou une matrice pour les coordonnées x, y, et pour les angles ainsi qu'un autre tableau dans lequel on entrera si l'objet est désactivé ou pas.
Comment ça marche un tableau ? Concrètement c'est très utile en ruby, un tableau s'initialise avec la commande "@variable = []" où l'on crée en fait un tableau vide ; après quoi il suffit d'entrer "@variable[valeur] = valeur_correspondante" ce qui permet d'assigner à un nombre un autre nombre ou, comme ici, une coordonnée pour chacun des points sans avoir à créer une variable pour chaque point.
Enfin on initialise et on assigne une coordonnée et un angle à chacun des points de 0 à @n, c'est à dire tous.
@y_rect correspond à la position @y du rectangle de sélection, qui restera fixe sur la première case (d'où le @y[0] qui correspond à la coordonnée y du premier point).

Portion de code : Tout sélectionner

1
2
3
4
5
6
7
8
9
10
@column_max = 1
    @item_max = commands.size
    @commands = commands
    @vitesse = vitesse
    @move = 0
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    self.contents.font.name = $fontface
    self.contents.font.size = $fontsize
    refresh
    self.index = 0


Du code (lol), ici on donne le nombre de colonne et on fait correspondre la variable locale "commands" interne à la méthode "initialize" à une variable locale propre à la classe du script "@commands" (caractérisée par l'@ devant, il existe un dernier type de variable, celles précédées d'un $ et qui sont accessibles quelles que soient les classes des scripts, ces variables sont dites "variables globales" par opposition bien sûr aux variables locales ; il existe un autre type de variable, celle précédées d'un @@ et qui correspondent aux variables précédées de rien du tout je crois (comme "commands" ici)).
On fait de même pour la vitesse ; on définie une variable "move" qui va déterminer combien de fois et dans quel sens les options ont été déviées.
On définit ensuite une bitmap contenant nos options, on assigne obligatoirement une police et une taille de police (ici les polices et tailles normales du jeu, données par les deux variables globales).
On lance la méthode refresh pour remplir notre fenêtre et on définie l'index en lançant la méthode du même nom (en effet self renvoie ici à la variable qui fait partie de la classe "Window_Command_Rotation" et lui fait exécuter la méthode "index" par le biais d'un point (ainsi @variable.machin effectuera la méthode "machin" de la variable "@variable" si cette variable appartient à une classe (ici "Window_Command_Rotation") et si dans cette classe ou ses supérieures la même méthode "machin" est définie (sinon vous aurez un message d'erreur))).

Portion de code : Tout sélectionner

1
2
3
4
5
6
def refresh
    self.contents.clear
    for i in 0...@item_max
      draw_item(i, color_item(@angle[i], i))
    end
  end



La méthode refresh, elle sert à remplir la fenêtre avec nos options ; tout d’abord on commence par effacer le contenu de la fenêtre ("self.contents.clear"), ensuite pour chaque objet de 0 à @item_max (donc pour toutes nos options), on va lancer la méthode qui va dessiner notre objet, en mettant entre parenthèse i, le numéro de l’objet à dessiner et la méthode color_item(angle, numéro) qui va renvoyer la valeur d’une couleur en fonction du numéro de l’objet et de son angle au centre.

Portion de code : Tout sélectionner

1
2
3
4
5
  def draw_item(index, color)
    self.contents.font.color = color
    rect = Rect.new(@x[index], @y[index], self.contents.width - 8, 32)
    self.contents.draw_text(rect, @commands[index])
  end



Voilà ici la méthode qui va nous permettre de dessiner chaque objet grâce à deux information : le numéro de l’objet (index) et sa couleur (color) qui se présente sous la forme Color.new(rouge, bleu, vert, luminosité). On affecte ladite couleur à la couleur de police du contenu de la fenêtre ("self.contents.font.color = color" ou "color" est la valeur renvoyée par la méthode "color_item" et est variable selon l'angle de la commande).
On définit ensuite un rectangle dans lequel va être affiché notre option ("rect = Rect.new(x, y, larg, long)" où x et y sont les positions respectives du point haut-gauche du rectangle par rapport au point haut droite de la fenêtre), on y affecte les coordonnées x et y correspondantes au numéro du point (calculées juste avant).

Portion de code : Tout sélectionner

1
2
3
4
5
6
7
8
  def color_item(angle, i)    
    if @item_disabled[i] == true
      transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI
    else
      transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI + 50
    end
    return Color.new(255, 255, 255, transparence)
  end



Alors là vous vous souvenez de la méthode qui définie la couleur du point en fonctionne de son angle ? Ben wala, c'est elle ^^
Bon alors voilà comment elle se présente : tout d'abord on vérifie si l'objet dont on veut calculer la couleur est désactivé ou pas, auquel cas on se gardera d'ajouter 50 à l'opacité, ce qui reviendra à retrancher 50.
Ensuite on calcule la transparence : Math.acos(Math.cos(x)) sert à donner la mesure principale de l'angle (enfin j'crois) ; on ajoute π à l'angle pour lui faire faire un demi-tour de cercle, de sorte que la transparence varie dans le bon ordre.
Je ne saurais exactement vous décrire cette formule mais l'on utilise la proportionnalité pour obtenir une valeur entre 0 et 205 avec un angle entre -180° et 180° (et donc une valeur entre 50 et 255 pour les objets non désactivés en ajoutant dans tous les cas 50) car j'ai fais ça un peu par tâtonnement (mais vous verrez si vous enlevez le "+Math::PI" votre transparence va varier dans le mauvais sens ...
Pour finir on renvoie un couleur grâce à la commande "return" qui revient à l'endroit où on avait appelé la méthode et transmet la couleur calculée.

Portion de code : Tout sélectionner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def move_item(sens, vitesse = @vitesse)
    d = vitesse
    @move += sens
    loop do
      self.contents.clear
      for i in 0...@n
        @x[i] = @ell * -Math.cos((@angle[i]*(d-1) + @dist*(i+@move) )/d)  + @ell + 4
        @y[i] = @r * Math.sin( (@angle[i]*(d-1) + @dist*(i+@move) )/d) + @r + 8
        @angle[i] = (@angle[i]*(d-1) + @dist*(i+@move) )/d
        draw_item(i, color_item(@angle[i], i))
      end
      Graphics.update
      d -=1
      if d == 0
        break
      end
    end
  end


Dans cette méthode l'on va créer l'animation de rotation.
Le "d" de la durée (cf. 2) va correspondre à la vitesse au départ. On ajoute à @move le sens de déplacement, +1 on tourne dans un sens, -1 dans l'autre (ce qui revient à ajouter ou retrancher 1) ; @move nous renseigne sur le nombre de fois où l'on a tourné notre système (c'est en quelque sorte l'index qui permet le positionnement graphique).
On crée alors une boucle infinie ("loop do") au début de laquelle on supprime le contenu (écrits) de la fenêtre/window ("self.contents.clear").
Ensuite l'on va redéfinir pour chaque point entre i et @n (le nombre max d'objet) leurs coordonnées carthésiennes et leur angle au centre (et ce grâce à la commande "for i in 0...@n" où 0 constitue une valeur de départ et @n le nombre maximum ; à noter qu'on exclue ce nombre maximum des valeurs que va prendre successivement i si l'on met trois points de suspension alors qu'on l'inclue lorsque l'on ne met que deux points (ainsi pour "for i in 0..3" i sera égal à 0, puis 1, 2 et 3 alors que pour "for i in 0...3" i sera égal à 0, puis 1 et 2)).
Bon les égalités déterminant les coordonnées des points je pense que vous les avez comprises (cf. l'approche théorique), après cela bien sûr l'on dessine les objets avec leur nouvelles coordonnées.
Ensuite on met à jour les graphismes (sinon on ne voit pas d'anim', on passe directement de l'état initial où d == @vitesse à l'état final où d == 0, c'est-à-dire jusqu'à ce que l'on mette à jour les graphismes.
Ensuite on retranche 1 à d, de sorte que les coordonnées évoluent, et si d == 0, on casse la boucle, c'est-à-dire qu'on en sort ("break"), car évidemment on ne peut pas diviser par zero et donc notre script bogguerait s'il venait à avoir à effectuer la division par d lorsque d == 0.

Portion de code : Tout sélectionner

1
2
3
cursor_width = self.width / @column_max - 32 - 2*@ell
    x = @index % @column_max * (cursor_width + 32)
    self.cursor_rect.set(x, @y_rect, cursor_width, 32)



Dans la méthode update_rect, on définie une largeur de curseur fixe, on y retranche 2 fois la largeur de l'ellipse, de sorte que ce ne soit pas trop grand (enfin, ça ça s'fait un peu au feeling ^^), on définie la position x du rectangle, sa position y étant déjà choisie au début.
Ainsi notre curseur sera fixe alors que seules nos commandes se déplaceront.

Portion de code : Tout sélectionner

1
move_item(-1)


Portion de code : Tout sélectionner

1
move_item(1)


Dans la méthode update, si l'on appuie sur bas nos commandes se déplaceront vers le bas d'un cran si l'on met "-1" et si l'on appuie sur haut elles se déplaceront vers le haut d'un cran si l'on met "1".




Voilà, c'est la fin du tuto, vous remarquerez que je n'ai pas expliquées certaines méthodes ; c'est tout simplement parce que je ne les ai pas modifiées, donc je ne me suis pas penché dessus pour les comprendre et j'ai donc la flemme de le faire :P


PS : Côté puissance, c'est pas trop gourmand je trouve. M'enfin ça rafraîchit quand même plusieurs fois la fenêtre par seconde, et ça dépend du nombre d'éléments et de la taille de votre fenêtre de sélection.




Exemples - posté le 24/12/2009 à 19:03:32 (2021 messages postés)

❤ 0

Pff.

Franchement, ya plus simple pour éviter les smilets dans les scripts:

Portion de code : Tout sélectionner

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#============================================================================== 
# Window_Command_Rotation 
#------------------------------------------------------------------------------ 
#============================================================================== 
class Window_Command_Rotation < Window_Base 
#-------------------------------------------------------------------------- 
attr_reader :index 
attr_reader :help_window 
#-------------------------------------------------------------------------- 
def initialize(width, commands, vitesse = 10, largeur=24, rayon=nil) 
super(0, 0, width, commands.size * 32 + 32) 
@n = commands.size 
if rayon == nil 
@r = @n*8 + 8 
else 
@r = rayon 
end 
@ell = largeur 
@dist = Math::PI * 2/@n 
@x = [] 
@y = [] 
@angle = [] 
@item_disabled = [] 
for i in 0...@n 
@x[i] = @ell * -Math.cos(@dist*i) + @ell + 4 
@y[i] = @r * Math.sin(@dist*i) + @r + 8 
@angle[i] = @dist*i 
end 
@y_rect = @y[0] 
@column_max = 1 
@index = -1 
@item_max = commands.size 
@commands = commands 
@vitesse = vitesse 
@move = 0 
self.contents = Bitmap.new(width - 32, @item_max * 32) 
self.contents.font.name = $fontface 
self.contents.font.size = $fontsize 
refresh 
self.index = 0 
end 
# ------------------------------------ 
def refresh 
self.contents.clear 
for i in 0...@item_max 
draw_item(i, color_item(@angle[i], i)) 
end 
end 
# ------------------------------------ 
def draw_item(index, color) 
self.contents.font.color = color 
rect = Rect.new(@x[index], @y[index], self.contents.width - 8, 32) 
self.contents.draw_text(rect, @commands[index]) 
end 
# ------------------------------------ 
def disable_item(index) 
@item_disabled[index] = true 
refresh 
end 
# ------------------------------------ 
def move_item(sens, vitesse = @vitesse) 
d = vitesse 
@move += sens 
loop do 
self.contents.clear 
for i in 0...@n 
@x[i] = @ell * -Math.cos((@angle[i]*(d-1) + @dist*(i+@move) )/d) + @ell + 4 
@y[i] = @r * Math.sin( (@angle[i]*(d-1) + @dist*(i+@move) )/d) + @r + 8 
@angle[i] = (@angle[i]*(d-1) + @dist*(i+@move) )/d 
draw_item(i, color_item(@angle[i], i)) 
end 
Graphics.update 
d -=1 
if d == 0 
break 
end 
end 
end 
# ------------------------------------ 
def color_item(angle, i) 
if @item_disabled[i] == true 
transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI 
else 
transparence = Math.acos(Math.cos(angle+Math::PI))*205/Math::PI + 50 
end 
return Color.new(255, 255, 255, transparence) 
end 
# ------------------------------------ 
def index=(index) 
@index = index 
if self.active and @help_window != nil 
update_help 
end 
update_cursor_rect 
end 
#-------------------------------------------------------------------------- 
def row_max 
return (@item_max + @column_max - 1) / @column_max 
end 
#-------------------------------------------------------------------------- 
def top_row 
return self.oy / 32 
end 
#-------------------------------------------------------------------------- 
def top_row=(row) 
if row < 0 
row = 0 
end 
if row > row_max - 1 
row = row_max - 1 
end 
self.oy = row * 32 
end 
#-------------------------------------------------------------------------- 
def page_row_max 
return (self.height - 32) / 32 
end 
#-------------------------------------------------------------------------- 
def page_item_max 
return page_row_max * @column_max 
end 
#-------------------------------------------------------------------------- 
def help_window=(help_window) 
@help_window = help_window 
if self.active and @help_window != nil 
update_help 
end 
end 
#-------------------------------------------------------------------------- 
def update_cursor_rect 
if @index < 0 
self.cursor_rect.empty 
return 
end 
row = @index / @column_max 
if row < self.top_row 
self.top_row = row 
end 
if row > self.top_row + (self.page_row_max - 1) 
self.top_row = row - (self.page_row_max - 1) 
end 
cursor_width = self.width / @column_max - 32 - 2*@ell 
x = @index % @column_max * (cursor_width + 32) 
self.cursor_rect.set(x, @y_rect, cursor_width, 32) 
end 
#-------------------------------------------------------------------------- 
def update 
super 
if self.active and @item_max > 0 and @index >= 0 
if Input.repeat?(Input::DOWN) 
if (@column_max == 1 and Input.trigger?(Input::DOWN)) or 
@index < @item_max - @column_max 
$game_system.se_play($data_system.cursor_se) 
@index = (@index + @column_max) % @item_max 
move_item(-1) 
end 
end 
if Input.repeat?(Input::UP) 
if (@column_max == 1 and Input.trigger?(Input::UP)) or 
@index >= @column_max 
$game_system.se_play($data_system.cursor_se) 
@index = (@index - @column_max + @item_max) % @item_max 
move_item(1) 
end 
end 
if Input.repeat?(Input::RIGHT) 
if @column_max >= 2 and @index < @item_max - 1 
$game_system.se_play($data_system.cursor_se) 
@index += 1 
end 
end 
if Input.repeat?(Input::LEFT) 
if @column_max >= 2 and @index > 0 
$game_system.se_play($data_system.cursor_se) 
@index -= 1 
end 
end 
if Input.repeat?(Input::R) 
if self.top_row + (self.page_row_max - 1) < (self.row_max - 1) 
$game_system.se_play($data_system.cursor_se) 
@index = [@index + self.page_item_max, @item_max - 1].min 
self.top_row += self.page_row_max 
end 
end 
if Input.repeat?(Input::L) 
if self.top_row > 0 
$game_system.se_play($data_system.cursor_se) 
@index = [@index - self.page_item_max, 0].max 
self.top_row -= self.page_row_max 
end 
end 
end 
if self.active and @help_window != nil 
update_help 
end 
update_cursor_rect 
end 
end


En tout cas, c'est pas pour cafter, mais sa rend super bien!

Bouh.


ixsuixwzone - posté le 12/06/2011 à 09:33:52 (2453 messages postés)

❤ 0

:surpris enorme :surpris
vu et adopte !

| Âmes Bannies - Demo 0.2 |

Suite à de nombreux abus, le post en invités a été désactivé. Veuillez vous inscrire si vous souhaitez participer à la conversation.

Haut de page

Merci de ne pas reproduire le contenu de ce site sans autorisation.
Contacter l'équipe - Mentions légales

Plan du site

Communauté: Accueil | Forum | Chat | Commentaires | News | Flash-news | Screen de la semaine | Sorties | Tests | Gaming-Live | Interviews | Galerie | OST | Blogs | Recherche
Apprendre: Visite guidée | RPG Maker 95 | RPG Maker 2003 | RPG Maker XP | RPG Maker VX | RPG Maker MV | Tutoriels | Guides | Making-of
Télécharger: Programmes | Scripts/Plugins | Ressources graphiques / sonores | Packs de ressources | Midis | Eléments séparés | Sprites
Jeux: Au hasard | Notre sélection | Sélection des membres | Tous les jeux | Jeux complets | Le cimetière | RPG Maker 95 | RPG Maker 2000 | RPG Maker 2003 | RPG Maker XP | RPG Maker VX | RPG Maker VX Ace | RPG Maker MV | Autres | Proposer
Ressources RPG Maker 2000/2003: Chipsets | Charsets | Panoramas | Backdrops | Facesets | Battle anims | Battle charsets | Monstres | Systems | Templates
Ressources RPG Maker XP: Tilesets | Autotiles | Characters | Battlers | Window skins | Icônes | Transitions | Fogs | Templates
Ressources RPG Maker VX: Tilesets | Charsets | Facesets | Systèmes
Ressources RPG Maker MV: Tilesets | Characters | Faces | Systèmes | Title | Battlebacks | Animations | SV/Ennemis
Archives: Palmarès | L'Annuaire | Livre d'or | Le Wiki | Divers