Développement de jeux vidéo indépendants
Forum création de jeux vidéo indépendants Mon compte Relite

Se rappeler ? S'inscrire
Jeux vidéo Jeux vidéo indépendants Création de jeux vidéo Finance et emploi jeux vidéo
Dictionnaire du jeu vidéo
Jeux vidéo indépendants Actualité jeux vidéo indépendants Jeux indépendants Tests de jeux vidéo indépendants Jeux indépendants à venir Dossier indy games Solutions jeux vidéo indépendants Vidéos jeux vidéo indépendants Jeux à télécharger Forum création de jeux
Forum création de jeux Mon compte Relite Liste des membres Relite Mes points Relite Derniers messages de Relite Régles du forum Relite Chercher


Relite - Création de jeux vidéo » Développement spécifique sur logiciels » Autre logiciels de création de jeux » Tutoriaux autre logiciels de création » [Ruby / Gosu] Cours Complet

Réponse
  3 links from elsewhere to this Post. Click to view. #1 (permalink)  
Vieux 17/01/2009, 17h55
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut [Ruby / Gosu] Cours Complet

Bonjour à tous ! Je me suis mis en tête de partager avec vous le fruit de mes recherches dans le développement Gosu Ruby.

Je n'ai pas la prétention de vous apprendre à développer en Ruby, ni même de dire que ce que je fais est la bonne façon de procéder. En revanche, je peux dire que ce que je fais fonctionne.

Place donc à un lonnnnnnnnng cours où je mettrai le maximum d'informations sur cette librairie fantastique.

Sur ces bonnes paroles : DÉBUT DU TUTORIEL.

Voilà bien longtemps que je souhaite rédiger ce tutoriel, suite à un constat malheureux mais pourtant bien réel : il n’existe quasiment aucune source sur la toile pour apprendre à développer des jeux vidéos en Ruby.

La plupart sont en anglais, voire en japonais, et bien souvent on perd énormément de temps à rechercher comment faire telle ou telle chose en Ruby pourtant largement documentée en C++, mais pratiquement jamais dans notre langage préféré.

Je souhaite ici vous exposer le fruit de mes recherches. J’utilise en ce qui me concerne les librairies Gosu, Ruby SDL et Ruby OpenGL. Dans un premier temps, je vais vous présenter Ruby Gosu.

Pré-requis : une connaissance correcte de la programmation Ruby, qui ne sera pas abordée ici pour se concentrer sur l'apprentissage de la librairie Gosu.

Ruby Gosu : programmation de jeux vidéos en toute simplicité

Installation :

Ruby Gosu, c’est une librairie fantastique pour le développement de jeux vidéo écrite par Julian Raschke. Bien que principalement dédiée au développement 2D , elle intègre OpenGL pour permettre d’utiliser la 3D dans une certaine mesure.

Voici tout d’abord trois liens :
Site officiel : http://code.google.com/p/gosu/
Lien de téléchargement : http://code.google.com/p/gosu/downloads/list (version gosu-windows-ruby)
Documentation : http://code.google.com/p/gosu/wiki/RubyReference

Pour l’installation sous Windows, voici comment procéder :
- Il vous faut bien sûr avoir Ruby d’installé sur votre machine. Dans le cas contraire, téléchargez donc la dernière version ici : http://www.ruby-lang.org/fr/downloads/
- Ensuite, téléchargez Ruby Gosu dans le lien donné plus haut. Décompressez l’archive, vous obtiendrez deux fichiers dans le sous-dossier lib : gosu.so et fmod.dll. Le fichier gosu.so est à placer dans (VotreRépertoireRuby)\lib\ruby\site_ruby\1.8\i386-msvcrt et le fichier fmod.dll dans le dossier de votre projet.

Et c’est tout ! L’installation est donc très simple. La librairie n’impose aucune dépendance, et vous n’aurez aucun problème pour l’utiliser.
Le dossier examples vous sera également bien utile pour découvrir comment fonctionne la librairie. Notez tout de même que certains exemples nécessitent d'autres dépendances, comme RMagick ou encore Chipmunk.

Pour vérifier que l’installation s’est bien déroulée, lancez donc une invite de commandes via Démarrer>Exécuter, tapez irb puis require ‘gosu.so’. Ruby Interactif devrait vous retourner true. Dans le cas contraire, revoyez votre installation.

A noter qu'il existe désormais une version Gem de Ruby Gosu, ce qui peut dans une certaine mesure simplifier l'installation, déjà peu complexe.

Utilisation :

Ruby Gosu est maintenant installé, voyons comment l’utiliser. En Ruby, vous pouvez programmer dans n’importe quel éditeur de texte. Ceci étant dit, je vous recommande d’utiliser un IDE, bien pratique, car vous aurez la coloration syntaxique, la possibilité d’avoir tous vos fichiers sources en simultané sous forme d’onglets ou encore la facilité de pouvoir lancer votre projet directement.

Bien que critiqué par de nombreux développeurs, je suis assez friand de Scite, IDE fourni par défaut avec Ruby.

Premier projet Ruby Gosu sous Scite :

Lancez Scite (un raccourci doit avoir été crée dans le menu Démarrer> programmes> Ruby).

Par défaut, un onglet Untitled est ouvert. Il correspond à un fichier source vide sans langage attribué.

La première chose à faire, c’est de l’enregistrer sous un nom contenant l’extension .rb (extension propre au langage Ruby). Ainsi, Scite fera correspondre une coloration syntaxique propre au Ruby à votre code.

La seconde chose à faire est d’inclure la librairie Gosu à votre programme. Pour ce faire, il suffit de taper la ligne require ‘gosu.so’.

Code:
require 'gosu.so'
J’ai nommé mon programme program.rb. Vous pouvez l’enregistrer où bon vous semble sur votre disque dur et sous le nom que vous voulez, tant qu’il contient l’extension .rb.

Sous Scite, vous pouvez masquer / afficher la console via F8. Vous lancez votre programme via F5. Si je lance le programme maintenant et que j’affiche la console, j’obtiens ceci :

Code:
>ruby program.rb
>Exit code: 0
La console nous indique qu’elle a exécuté ruby program.rb, ce qui correspond à l’action de lancer Démarrer > Exécuter > cmd > ruby program.rb. Taper F5, c’est quand même moins fastidieux non ? La console nous retourne Exit code : 0, soit la fin tout à fait correcte d’un programme, sans erreur. Tout va bien.

Ouvrir une fenêtre :


Il y a plusieurs manières d’ouvrir une fenêtre sous Gosu, mais la plus simple consiste à dériver une classe fille de la classe Gosu ::Window. Ainsi, on pourra très facilement profiter des méthodes complexes de cette classe pré fournie par quelques lignes de code très simples.

Appelons notre classe fenêtre MainWindow. Cette classe doit donc être déclarée classe fille de la classe Gosu ::Window. Dans le constructeur de notre classe, nous ferons appel à celui de la classe mère via la méthode super(), dans laquelle nous donnerons les arguments suivants : hauteur, largeur, plein écran (boolean).

Ces arguments sont demandés dans la définition de la méthode initialize de la classe Gosu::Window. Il est donc logique de les fournir via la méthode super(), notre classe étant héritée de Gosu::Window. La documentation nous donne en effet :

Gosu::Window def initialize(width, height, fullscreen, update_interval = 16.666666)

Ce sont les arguments incontournables pour s’approprier notre fenêtre. L’argument suivant, bien qu’il ait une valeur par défaut, peut grandement intéresser : il s’agit du framerate. Gosu attend en millisecondes le temps que nous devons attendre avant de mettre à jour la fenêtre. Ainsi, nous passerons pour argument 1000/framerate. Par défaut, le framerate est défini à 60 frames par secondes (soit 1000/60 = 16.666666). Fixons le framerate à 40 FPS par exemple.

Codons donc sans plus tarder notre classe MainWindow, qui ouvrira une fenêtre en fenêtré de 640*480 pixels, 40 frames par secondes et dont nous changerons le titre via la méthode caption.

Code:
require 'gosu.so'

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false, 1000/40)
    self.caption = "Gosu Window"
  end
end

MainWindow.new.show
Via l’appel du constructeur de notre nouvelle classe, nous créons un objet MainWindow. Sur la même ligne, j’ai appelé la méthode show afin que la routine se lance. Cette méthode show fait en sorte que la fenêtre se lance et appelle à chaque frame les méthodes update et draw. L’application tourne tant que la méthode close n’est pas appelée. Cette méthode est automatiquement appelée lorsque la fenêtre est fermée manuellement par l’utilisateur via la croix.

Pour les non initiés à l'héritage Ruby, notre classe étant héritée de Gosu::Window, elle peut en toute logique appeler les méthodes show, draw et update. Il faudra bien sûr redéfinir les méthodes draw et update, vides par défaut.

Tapez F5 et contemplez votre œuvre.

Pour le moment, pas grand-chose : une fenêtre noire se lance. Reconnaissez tout de même que ce n’est pas souvent qu’on a le luxe d’ouvrir une fenêtre avec aussi peu de code. Bien sûr, évitez de passer en plein écran pour le moment, car nous n’avons encore rien spécifié pour permettre de fermer le programme sans avoir accès à la barre d’outils de la fenêtre.

Au passage, nous allons être amenés à utiliser beaucoup de méthodes de la librairie Gosu. Il se peut que vous soyez lassés de systématiquement spécifier le name space Gosu ::. Si vous souhaitez vous en passer, il suffit de rajouter en seconde ligne de votre programme :

Code:
include Gosu
Ainsi, vous pourrez simplifier par exemple Gosu ::Window pour Window. Pour ma part, j’évite d’utiliser ce procédé. Déjà, on évite ainsi les doublons de méthodes qui auraient le même nom entre Gosu :: et votre application. Ces cas sont rares, mais existent. Mais surtout, j’aime savoir du premier coup d’œil quand une méthode appartient à Gosu :: ou si elle appartient à mon propre programme.

Fermer le programme via une touche :

Et si nous voulions que l’application soit fermée via Escape, pour par exemple permettre un mode plein écran ? Gosu permet de le faire via plusieurs méthodes, mais la plus simple dans ce cas de figure est d'utiliser la méthode button_down(id) de Gosu::Window.

Je rappelle que vu que notre classe MainWindow est déclarée comme fille de la classe Window de Gosu, elle peut appeler les méthodes de la classe mère, dont fait donc partie button_down(id). Nous allons donc surcharger la méthode button_down(id) dans notre classe MainWindow.

Code:
require 'gosu.so'

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, true)
  end

  def button_down(id)
    close if id == Gosu::Button::KbEscape
  end
end

MainWindow.new.show
Ainsi, appuyez sur F5 et vous verrez que le programme se lancera en plein écran (du fait que nous ayons passé true comme valeur à l’argument full screen dans le constructeur de la fenêtre) et que l’on peut fermer la fenêtre en pressant Escape sur le clavier.

Les méthodes button_down(id) et button_up(id) sont appelées respectivement lorsqu'une touche est pressée ou lâchée. La constante correspondant à la touche pressée ou relâchée est transmise à l'argument id, permettant donc de décider d'une action en fonction de cette valeur.

Gosu::Window dispose d'une autre méthode intéressante : la méthode button_down?(id). Cette méthode prend pour argument une constante de touche et renvoie true si la touche est actuellement pressée, false dans le cas contraire.

Code:
exit if button_down?(Gosu::Button::KbEscape)
La boucle infinie dans Gosu :

Tout programme fonctionne indéfiniment grâce à une boucle, tant que l’utilisateur ou une condition spécifique n’a pas demandé le contraire. Dans Gosu, la boucle est lancée lorsqu’une instance de fenêtre a été créée et la méthode show appelée, ce que nous avons fait via le code MainWindow.new.show.

La boucle infinie fonctionne ainsi dans Gosu : les méthodes update et draw sont appelées puis la fenêtre est mise à jour suivant le délai Frame Delay passé dans le constructeur, 1000/60 millisecondes donc dans notre exemple.

Nous devons donc surcharger nos méthodes update et draw afin qu’il se passe quelque chose dans notre fenêtre. La boucle infinie est donc ainsi effectuée :

Code:
require 'gosu.so'

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, true)
  end

  def button_down(id)
    close if id == Gosu::Button::KbEscape
  end

  # début de boucle infinie
  def update
    # du code
  end

  def draw
    # du code
  end
  # fin de boucle infinie
end

MainWindow.new.show
Afficher une image sous Gosu :

Bien ! Nous avons maintenant tout ce qu’il nous faut pour afficher une image sous Gosu. Pour afficher une image, il nous faut construire un objet de la classe Gosu ::Image. Comme je le recommande à chaque fois que vous souhaitez utiliser une classe de la librairie Gosu, faites donc un petit tour dans la documentation.

Code:
Class Gosu ::Image def initialize(window, filename_or_rmagick_image, hard_borders, [srcX, srcY, srcWidth, srcHeight])
Le constructeur de la classe Image a donc besoin de quelques arguments pour pouvoir être appelé et donc créer notre image.
  • - Le premier argument, window, est la fenêtre dans laquelle doit être créée l’image. Nous utiliserons self, qui correspond à notre fênêtre elle-même.

    - Ensuite, le constructeur a besoin du filename ou bien d’une image rmagick (Gosu entretient des relations avec cette autre librairie). Nous utiliserons filename, qui permet de charger n’importe quel type d’image usuel.

    - Enfin, le constructeur attend un bouléen pour savoir si nous devons ou non afficher un flou sur les bordures de l’image. En règle générale, nous utiliserons false, afin de préserver l’aspect d’origine de notre image.



J’ai crée cette image il y a quelques temps, un genre de « splash screen », comme à l’époque de RPG Maker 2000. Je trouvais important de dévoiler les outils utilisés pour créer un jeu, dans le sens où déjà c’est une manière de remercier l’auteur d’une librairie, mais également car j’aurais parfois aimé savoir comment était conçu tel ou tel jeu qui m’avait marqué.

Vous pouvez bien sûr utiliser cette image si vous comptez développer en Ruby en utilisant Gosu.

Au passage, lors de la dernière mise à jour de la librairie, l'auteur a changé son logo, qui ressemble désormais à ceci :



Nous allons afficher cette image dans notre fenêtre. Afin de ne pas charger cette image à chaque frame, nous allons la charger dans le constructeur de la fenêtre. Ce ne sera pas toujours la solution idéale, mais ce tutoriel n’a que pour but de vous montrer les bases de la librairie, donc la construction de votre code sera plus réfléchie et donc adaptée à vos besoins par la suite.

Reprenons donc notre constructeur MainWindow pour y ajouter l’image.

Code:
require 'gosu.so'

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, true)
    @image = Gosu::Image.new(self, "image.png", false)
  end

  def button_down(id)
    close if id == Gosu::Button::KbEscape
  end

  # début de boucle infinie
  def update
    # du code
  end

  def draw
    @image.draw(0, 0, 0)
  end
  # fin de boucle infinie
end

MainWindow.new.show
Nous ajoutons donc dans le constructeur le code @image = Gosu ::Image.new(self, « image.png », false). Ainsi, nous créons un objet de type Gosu ::Image, dont le parent est la fenêtre même, le fichier image se trouve à la racine du projet et se nomme image.png et dont les bordures ne sont pas floues.

Reste à ajouter le bout de code dans la méthode draw afin de l’afficher dans la fenêtre. La documentation nous donne :

Code:
draw(x, y, z, factor_x=1, factor_y=1, color=0xffffffff, mode=:default)
On voit donc que la méthode draw attend comme paramètres obligatoires x, y et z, et permet de définir d’autres paramètres comme le zoom, la couleur et le mode d’incrustation de cette couleur. Nous commencerons doucement avec un affichage simple. La coordonnée Z permet le placement dans la profondeur, de sorte que plus Z est grand, plus l’image sera au-dessus de la pile.

Nous avons donc ajouté notre premier code à la méthode draw de notre classe MainWindow ! Ce code demande tout simplement d’afficher l’image chargée dans le constructeur aux coordonnées (0, 0, 0). Nous obtenons en lançant le programme une fenêtre contenant notre image !

Nous avons ainsi affiché notre première image sous Ruby Gosu. Notez que si vous utilisez des PNG, la transparence des pixels doit être totale pour en bénéficier. Pas de gestion du color key pour les PNG, mais bien l’absence de pixels. Sous Photoshop, par exemple, cette transparence est représentée par un damier blanc et gris.

Gosu gère aussi l’alpha blending, en ce sens la transparence partielle est préservée, ce qui peut donner lieu à des résultats très sympas, comme afficher des ombres par exemple.

Pour ce qui est de la transparence des images BMP, Gosu utilisera la couleur [255, 0, 255] comme Color Key, qui sera donc effacée lors de son affichage.

Gosu permet de charger les formats usuels comme les BMP, PNG ou JPEG par exemple. Nous avons vu ici la première méthode pour afficher une image, il en existe une autre très pratique : Gosu ::Image.load_tiles.

Code:
Gosu ::Image load_tiles(window, filename_or_rmagick_image, tile_width, tile_height, hard_borders)
Cette méthode crée un tableau de Gosu ::Image en découpant une image via les arguments passés dans le constructeur. Ainsi, si nous passons par exemple 32 en tile_width et 32 en tile_height, nous obtiendrons un découpage de l’image passée en filename de 32*32 et donc un tableau d’autant d’éléments que ce découpage en produit. Par exemple, si on utilise une map faite de tiles, on utilisera plutôt cette méthode. On pourra alors accéder à chaque tile via la méthode draw appelée sur une cellule du tableau.

Un exemple en code :
Code:
@tileset = Image.load_tiles(self , « tileset.png », 32, 32, false)
@tileset[0].draw(0, 0, 0)
J’utilise cette méthode pour mes personnages par exemple, afin de mettre toutes les positions du personnage dans la même image.

Habilement utilisé, ce constructeur permet donc de découper une image directement dans Gosu, ce qui évite de devoir prévoir une méthode de stockage des images tilées.

On voit donc ici qu’il est très simple d’afficher une image dans Gosu. Ainsi, il est par exemple très facile de créer une classe Sprite, qui contiendra un objet de type Gosu ::Image et des coordonnées propres @x, @y, @z afin que ce sprite puisse s’afficher à une position propre. Ceci faisant partie de la construction du moteur, nous y reviendront plus tard, afin de nous concentrer sur les bases pour l’instant.

Jouer une musique :

Gosu intègre FMOD pour une gestion du son aisée et un rendu largement suffisant pour la plupart des types de jeu. Bien que ça n'ai jamais été une priorité au cours de mes différents développements, la gestion du son est incontournable pour un projet.

Gosu fournit une classe Gosu::Song, dont le constructeur nécessite pour arguments la fenêtre (comme pour toute classe de Gosu, en fin de compte) et le chemin qui mène à la musique.

Code:
# placer ce code dans la méthode initialize de la classe MainWindow
@song = Gosu::Song.new(self, "mon_dossier/ma_musique.mp3")
La musique est maintenant chargée. Pour la lancer, au moment souhaité, utiliser la méthode play. Ainsi, si on souhaite que la musique se lance au moment où la fenêtre s'ouvre, on ajoutera en fin de la méthode initialize :

Code:
class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Fenetre avec musique"
    @musique = Gosu::Song.new(self, "mon_dossier/ma_musique.mp3")
    @musique.play
  end
end

MainWindow.new.show
La méthode playing? renvoie true si la piste est en train d'être jouée, false dans le cas contraire (utile pour une boucle de savoir quand elle est arrêtée) et on peut spécifier le volume de la piste via la méthode volume (où 1 représente le volume le plus élevé et 0 un volume nul).

La méthode play prend un argument (optionnel) pour spécifier si la piste doit être jouée en boucle. Par défaut, elle ne sera jouée qu'une fois.

Ainsi, pour faire boucler la piste :

Code:
class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Fenetre avec musique"
    @musique = Gosu::Song.new(self, "mon_dossier/ma_musique.mp3")
    @musique.play(true) # looping a été passé comme valant true
  end
end

MainWindow.new.show
Pour ne pas changer avec cette lib, toujours très très accessible

Dessiner dans la fenêtre :

Nous avons vu comment afficher une image dans notre fenêtre, mais Gosu dispose également de méthodes de dessin brut.

Pour être précis, la classe Gosu::Window dispose de trois modes de dessin :
- dessin d'un segment entre deux points
- dessin d'un triangle
- dessin d'un rectangle.

Le système utilisé est simple quand on l'a compris.

- dessin d'un segment : définissons ensemble deux points, que nous nommerons point 1 et point 2. Je n'utilise pas A ou B pour mieux coller à la méthode Gosu. Ensuite, choisissons la manière de colorier ce segment. Si on choisit de faire un segment mono couleur, on prendra une unique valeur pour cette couleur, qui sera représentée par un objet de type Gosu::Color.

Si on choisit de faire un dégradé du point 1 au point 2, nous aurons besoin de deux couleurs. Simple et efficace.

Il existe plusieurs manières de créer un objet de la classe Gosu::Color. Ma préférée reste le constructeur initialize(a, r, g, b).

Ainsi, on peut facilement choisir sa couleur, et n'importe quel logiciel d'édition d'image permettra d'obtenir les valeurs à utiliser. Le premier champ, a (pour alpha), correspond à l'opacité de la couleur (de 0 à 255).

Créons donc un segment du point 1 situé en (0, 0) au point 2 situé en (15, 25), en dégradé du noir (255, 0, 0, 0) vers le blanc (255, 255, 255, 255).

La méthode est la suivante : draw_line(x1, y1, c1, x2, y2, c2, z=0, mode=:default).

Code:
require "gosu.so"

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Gosu Window"

    @black_color = Gosu::Color.new(255, 0, 0, 0)
    @white_color = Gosu::Color.new(255, 255, 255, 255)    
  end
  
  def draw
    self.draw_line(0, 0, @black_color, 15, 25, @white_color)
  end
end

MainWindow.new.show
Nous obtenons le résultat suivant :



Notez au passage qu'il existe un argument z, optionnel car ayant une valeur nulle par défaut. Il peut être utile de le spécifier si votre ligne doit passer par dessus un élément graphique. De plus, le mode de fusion est par défaut fixé à :default (aucun effet, donc) mais peut être défini comme :additive.

- dessin d'un triangle : draw_triangle(x1, y1, c1, x2, y2, c2, x3, y3, c3, z=0, mode=:default)



c'est le même principe que pour dessiner une ligne, à ceci bien sûr qu'il y a trois arguments de plus à spécifier : une couleur et deux coordonnées supplémentaires.

- dessin d'un rectangle : draw_quad(x1, y1, c1, x2, y2, c2, x3, y3, c3, x4, y4, c4, z=0, mode=:default)




même remarque que précédemment : encore trois valeurs de plus à spécifier que pour dessiner un triangle. A noter que l'ordre de lecture suit la lecture classique : de gauche à droite et de haut en bas.

Dessiner dans Gosu, c'est simple ! Les effets de dégradé inclus font qu'il est totalement possible de dynamiquement créer ses menus par exemple, sans avoir nécessairement recours à du Photoshop, par exemple. En jouant sur la manière de placer ses couleurs, on peut créer des dégradés droits, en diagonale... Comme on le souhaite en fait

Gestion de la souris dans Gosu :

Il n'y a pas dans Gosu de curseur visible de souris, ce qui peut être gênant pour quiconque en aurait besoin pour le déroulement de son jeu. Néanmoins, deux méthodes de la classe Gosu::Window permettent de récupérer les coordonnées x et y du pointeur actuel de la souris.

Ces deux méthodes sont :
- mouse_x
- mouse_y

Il est donc finalement très simple d'afficher le curseur de la souris.

Code:
require "gosu.so"

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Gosu Window"
    @mouse_pointer = Gosu::Image.new(self, "mouse_pointer.png", false)  
  end
  
  def draw
    @mouse_pointer.draw(mouse_x, mouse_y, 0)
  end
end

MainWindow.new.show
Vu qu'il n'y a rien dans ma fenêtre, j'ai mis Z = 0. Il va de soi qu'une fois la fenêtre bien remplie, la souris devant passer devant tous les éléments en règle générale, il serait plus approprié de mettre une valeur très grande pour être sûr qu'elle passe bien au-dessus de tous les éléments.

Je rappelle que Gosu gère le Z-buffer. En ce sens, toute méthode draw avec un z plus élevé dessinera l'image au-dessus de celle dont la méthode draw a un z plus faible. Lorsque le z est identique, la superposition se fait dans l'ordre de dessin : celui qui est dessiné après sera au-dessus de celui dessiné avant.

A noter enfin qu'il peut être nécessaire d'ajuster la position de l'image de curseur de souris en fonction de la manière dont est représenté le curseur. En effet, la position réelle du pointeur nous intéressant est celle effectivement pointée par le curseur. La classe Gosu::Image nous offre à cet effet les méthodes width et height, nous permettant ainsi d'obtenir respectivement la largeur et la hauteur de l'image.

Ainsi si le pointeur utilisé représente une flèche pointant en bas à droite, il faudrait dessiner l'image en haut à gauche de la position de la souris réelle (masquée par Gosu, donc), soit à mouse_x - largeur, mouse_y - hauteur, étant donné que le système de coordonnées de Gosu fixe l'origine du repère (0, 0) en haut à gauche de la fenêtre. On corrigerait donc ainsi la méthode draw de notre classe MainWindow :

Code:
  def draw
    @mouse_pointer.draw(mouse_x - @mouse_pointer.width, mouse_y - @mouse_pointer.height, 0)
  end
end
Pour la gestion des clics de souris, Gosu fournit des constantes :
Code:
MsLeft
MsMiddle
MsRight
MsWheelDown
MsWheelUp
On accède au bouton gauche, par exemple, via la constante Gosu::Button::MsLeft.

Pour utiliser facilement les boutons de la souris, on peut utiliser la même méthode que nous avions choisie pour fermer la fenêtre avec la touche Escape, et donc compléter la méthode button_down(id) de notre fenêtre.

Voici un code qui peut paraitre absurde dans l'idée, mais permet de bien se faire une idée de comment fonctionnent les méthodes button_down(id) et button_up(id) de la classe Gosu::Window.

Code:
require 'gosu.so'

class Window < Gosu::Window
  def initialize
    super(640, 480, false)
  end
  
  def button_down(id)
    close if id == Gosu::Button::MsLeft
  end
  
  def button_up(id)
    close if id == Gosu::Button::MsRight
  end
end
    
Window.new.show
Ce bout de programme ouvre une fenêtre qui se fermera sous deux conditions, en plus bien sûr de la fermeture par la croix de la barre d'outils
- appuyer sur le bouton gauche de la souris
- appuyer puis relacher le bouton droit de la souris.

Une nouvelle méthode vient d'être ajoutée pour la gestion de la souris, toujours propre à la classe Gosu::Window : set_mouse_position(x, y), qui permet comme son nom l'indique de spécifier les coordonnées de la souris.

Je pense que les bases nécessaires à l'utilisation de la souris sont maintenant posées, avançons.

Afficher un texte avec Gosu :

ATTENTION : ce qui suit est obsolète pour ceux qui utilisent la nouvelle version de Gosu : la 0.7.13. En effet, sur mes tests du jour, j'ai constaté qu'il n'y avait désormais plus aucun problème pour afficher des caractères accentués. Je laisse à titre d'archive et pour ceux qui utilisent des anciennes releases ce qu'il fallait faire avant, mais sur la dernière version (que je recommande chaudement), utiliser l'astuce ci-dessous engendre des soucis au niveau des caratères affichés.

Afficher un texte avec Gosu est à la fois très simple et une vraie torture pour nous, francophones. Le problème est que la librairie n'a pas été codée pour fonctionner avec nos caractères accentués. Après des heures et des heures de recherche j'ai enfin trouvé une solution qui fonctionne.

Gosu fournit la classe Gosu::Font. Pour charger une police, on utilise le constructeur très simple : initialize(window, font_name, height).

Window correspond bien sûr à la fenêtre où s'affiche la police, font_name renvoie au nom de la police ou au chemin vers un fichier .ttf et height représente la taille de la police.

Si vous utilisez un fichier font dans le constructeur que vous fournissez avec votre projet, il faut que le chemin vers ce fichier contienne le caractère "/". Ainsi, si votre font se trouve à la racine du projet :

Code:
@font = Gosu::Font.new(self, "./AGENCYR.TTF", 80)
Enfin, pour s'assurer que la font choisie sera présente sur n'importe quel système, on peut demander à Gosu de choisir lui-même une police système, via la méthode du module Gosu : default_font_name().

Pour dessiner un texte à l'écran on utilisera :
draw(text, x, y, z, factor_x=1, factor_y=1, color=0xffffffff, mode=:default)

Ainsi, dans une première version incomplète, nous aurons :

Code:
require "gosu.so"

class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Gosu Window"
    @font = Gosu::Font.new(self, "Georgia", 80)


  end
  
  def draw
    @font.draw("Un simple texte", 0, 0, 0)
  end
end

MainWindow.new.show
Ce qui nous donne à l'écran :



Le problème, c'est que Gosu n'affiche pas les caractères spéciaux, comme les accents. Il m'aura fallu des heures de recherche pour finalement trouver une solution : ré encoder le texte du format iso-8859-1 au format UTF-8.

Merci à Treb pour m'avoir donné l'astuce qui tue afin d'intégrer proprement la modification nécessaire à l'affichage d'un texte contenant les caractères accentués.

Code:
require "gosu.so"

class Gosu::Font
  alias original_draw draw
 
  def draw(text, x, y, z, factor_x=1, factor_y=1, color=0xffffffff, mode=:default, old = false)
    if old
      original_draw(text, x, y, z, factor_x, factor_y, color, mode)
    else
      original_draw(text.unpack('C*').pack('U*'), x, y, z, factor_x, factor_y, color, mode)
    end
  end
end 


class MainWindow < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Gosu Window"
    @font = Gosu::Font.new(self, "Georgia", 80)
  end
  
  def draw
    @font.draw("héhé !", 0, 0, 0)
  end
end

MainWindow.new.show
Nous obtenons enfin :



Si vous utilisez les méthodes draw_rel et draw_rot de la classe Gosu::Font, il faudra procéder de la même manière pour permettre les accents et donc également créer des alias pour ces méthodes.

D'autres fonctionnalités intéressantes :

Gosu est une librairie encore très active point de vue développement : son auteur travaille d'arrache pied et ajoute régulièrement bien des fonctionnalités.

Une des dernières méthodes ajoutées à la classe Gosu::Window est la méthode clip_to(x, y, w, h) do ... end.

Cette méthode faisait cruellement défaut à Gosu. Elle permet tout simplement de limiter le dessin à une portion de l'écran. Ainsi, on passe en argument les coordonnées du point haut-gauche du rectangle de dessin ainsi que la largeur et la hauteur de ce rectangle. A cette méthode, on passera un bloc de code Gosu.

Ce code Gosu s'il contient du dessin ne dessinera justement que dans ce rectangle. On pouvait en SDL effectuer ce crop en utilisant la structure SDL_Rect. Ainsi, on limitait la zone à blitter de la SDL_Surface source vers la SDL_Surface de destination.

Voyons un exemple concret d'utilisation de cette méthode clip_to. J'ai choisi par exemple de représenter une mini-map dans le coin haut-droit de la fenêtre. Une mini-map, c'est une carte à faible échelle qui représente une carte à échelle normale, permettant de savoir où se trouve par exemple le personnage du jeu dans le monde.

Voici une mini-map affreuse faite en 40 secondes sous Photoshop :


L'image fait 320*240 pixels. Dans notre fenêtre de 640*480, nous souhaitons que la mini-map n'occupe que 160*120 pixels dans le coin haut-droit de la fenêtre.

Voici une manière de n'afficher qu'une portion de la mini-map (160*120 pixels, donc), dans le coin haut-droit avec 10 pixels de marges par rapport au bord de la fenêtre.

Code:
require "gosu.so"

class Window < Gosu::Window
  def initialize
    super(640, 480, false)
    self.caption = "Mini Map : clip_to method"
    @miniMap = Gosu::Image.new(self, "miniMap.png", false)
    
  end
  
  def draw
    clip_to(self.width - 170, 10, 160, 120) do
      @miniMap.draw(self.width - 160, 0, 0)
    end
  end
end

Window.new.show
Ce qui donne à l'écran :



Je vous passe les détails du calcul des coordonnées réelles de la mini-map, de la position du pointeur de personnage, etc. car ce n'est pas le but ici. Mais remarquez comme la méthode clip_to peut s'avérer utile.

On a bien l'effet escompté : un crop de l'image sur 160*120 pixels. On peut utiliser cette méthode à bien des niveaux, par exemple limiter le dessin d'un texte à la portion en pixels qu'occupe une boite de dialogue.

En combinant les méthodes de Gosu, on peut ainsi arriver à recréer la structure SDL_Rect de SDL, qui manquait véritablement à Gosu.

Réalisation concrète : créer un menu type RMXP

Nous attaquons enfin notre première réalisation sérieuse sous Gosu. J'ai cherché un exemple qui permette d'utiliser la majorité de ce que j'ai exposé plus haut et j'ai opté pour la création du menu d'accueil de RPG Maker XP.



Nous allons donc essayer de s'approcher de ce menu. J'utiliserai très peu d'images pour ce programme, à savoir :
- les sprites de personnages


- des images de très petite taille pour les coins du menu :


Vous trouverez toutes ces images à l'adresse suivante : http://bestguigui.free.fr/tutoriel_g...l_menu/images/

L'objectif que je me suis fixé ici est de reproduire l'image précédente issue de RMXP, en ajoutant juste la possibilité de diriger un curseur animé dans le menu.

L'organisation du code est loin d'être parfaite, en un seul fichier .rb, mais c'est le principe que je veux exposer ici. Libre à vous de faire bien mieux. Pour les besoins de l'exercice, j'ai crée un semblant de classe Character, qu'il faudrait largement plus travailler.

Vous trouverez le code source complet ici :
http://bestguigui.free.fr/tutoriel_g...l_menu/init.rb

Voici ce que nous allons créer :



La copie n'est pas parfaite, car je l'ai personnalisée un peu selon mes goûts. Place au code :

Code:
require "gosu.so"

class Gosu::Font
  alias original_draw draw
 
  def draw(text, x, y, z, factor_x=1, factor_y=1, color=0xffffffff, mode=:default, old = false)
    if old
      original_draw(text, x, y, z, factor_x, factor_y, color, mode)
    else
      original_draw(text.unpack('C*').pack('U*'), x, y, z, factor_x, factor_y, color, mode)
    end
  end
end
Très classique jusque là : nous incluons Gosu à notre programme et nous appliquons la correction de la classe Font vu plus haut pour que les accents soient pris en compte lorsqu'on affiche un texte.

Code:
class Character
  attr_accessor :name, :job, :lvl, :pv, :pv_max, :pm, :pm_max, :path, :sprite, :exp, :exp_goal
  def initialize(name, job, path)
    @name = name
    @job = job
    @lvl = 1
    @pv = 25
    @pv_max = 25
    @pm = 10
    @pm_max = 10
    @path = path
    @sprite = nil
    @exp = 0
    @exp_goal = 25
  end
end
Il s'agit d'une classe Character très basique, qui ne demande comme arguments que le nom et job du personnage et le chemin vers le .png qui le représente. La classe attribue aux autres variables une valeur par défaut et j'ai ajouté un accesseur pour toutes ces variables afin de pouvoir les afficher dans le menu.

Nous prévoyons une variable @sprite qui sera chargée une fois le personnage ajouté à la fenêtre, car tout Gosu::Image a besoin d'une référence à la fenêtre où il sera affiché. On évite ainsi d'avoir à spécifier à chaque fois la fenêtre.

Cette classe est vraiment bâclée afin de ne permettre que ce qu'on souhaite ici : avoir des valeurs à afficher.

Code:
class Window < Gosu::Window
C'est ici que les choses sérieuses commencent. J'ai placé tout le reste du code dans cette classe Window, car le programme étant restreint à cet objectif, je pouvais me le permettre. Il va de soi que dans un jeu complet, il faudra organiser bien mieux les choses.

Code:
  def initialize
    super(640, 480, false)
    self.caption = "Système de menu".unpack('C*').pack('U*') 
    @font = Gosu::Font.new(self, "Verdana", 18)
    self.setup
  end
C'est le constructeur de notre fenêtre. Il fait appel au constructeur de sa classe mère (Gosu::Window) via super, pour créer une fenêtre de 640*480 pixels en fenêtré. J'ai changé le titre de la fenêtre et ai ajouté au titre la méthode .unpack('C*').pack('U*') car mon titre contient des accents.

Enfin, j'ai chargé une police de type Verdana, taille 18, et je fais appel à une méthode setup histoire de séparer un minimum les instructions.

Code:
  def setup
    # colors
    @white = Gosu::Color.new(255, 255, 255, 255)
    @blueBorder = Gosu::Color.new(255, 33, 35, 79)
    @blue1 = Gosu::Color.new(255, 66, 68, 120)
    @blue2 = Gosu::Color.new(255, 44, 45, 85) 
    @blue_text = Gosu::Color.new(255, 192, 224, 255)

    # textures
    @corners = Hash.new    
    @corners["top-left"] = Gosu::Image.new(self, "images/coin_haut_gauche.png", false)
    @corners["top-right"] = Gosu::Image.new(self, "images/coin_haut_droit.png", false)
    @corners["bottom-left"] = Gosu::Image.new(self, "images/coin_bas_gauche.png", false)
    @corners["bottom-right"] = Gosu::Image.new(self, "images/coin_bas_droit.png", false)    
    
    # timer
    @hours = 0
    @minutes = 0
    @seconds = 0
    @last_time = Gosu::milliseconds()
    
    # various
    @gold = 150
    @steps = 1230
    @characters = Array.new
    
    @cursor_x = 3
    @cursor_y = 19
    @cursor_opacity = 200
    @fading_type = "IN"
  end
Cette méthode setup me sert à créer des variables dont j'aurai besoin par la suite. J'ai essayé de les organiser un minimum. Il s'agit principalement de fixer les couleurs dont j'aurai besoin, les images du menu (les quatre coins de fenêtre) ainsi que des variables pour contenir les valeurs du menu comme l'or, les pas.

Enfin, j'ai déclaré un tableau @characters pour stocker les personnages et ai fixé quelques valeurs pour le curseur du menu, nous y reviendront.

Code:
  def addCharacter(character)
    @characters << character
    @characters[@characters.size - 1].sprite = Gosu::Image.new(self, @characters[@characters.size - 1].path, false)
  end
Cette méthode ne sert qu'à alimenter le tableau des personnages. Elle ajoute au tableau @characters un nouvel élément. De plus, elle crée l'objet Gosu::Image, puisque nous avons enfin la référence de la fenêtre, à savoir self, où doit s'afficher le personnage.

Code:
  def drawBox(x, y, w, h, z = 0)  
    #corners drawing
    @corners["top-left"].draw(x, y, 1)
    @corners["top-right"].draw(x + w - @corners["top-right"].width, y, 1)
    @corners["bottom-left"].draw(x, y + h - @corners["bottom-left"].height, 1)
    @corners["bottom-right"].draw(x + w - @corners["top-right"].width, y + h - @corners["bottom-right"].height, 1)
    
    # blue border
    self.draw_quad(x, y, @blueBorder, x + w, y, @blueBorder, x, y + h, @blueBorder, x + w, y + h, @blueBorder)     
    # white border
    self.draw_quad(x + 1, y + 1, @white, x + w - 1, y + 1, @white, x + 1, y + h - 1, @white, x + w - 1, y + h - 1, @white)    
    # blue gradient
    self.draw_quad(x + 3, y + 3, @blue1, x + w - 3, y + 3, @blue2, x + 3, y + h - 3, @blue1, x + w - 3, y + h - 3, @blue2) 
  end
Cette méthode me sert à créer une boite à la dimension et aux coordonnées souhaitées. Ainsi, je pourrai utiliser cette même méthode à chaque fois que j'aurai besoin d'un cadre.

Basiquement, il s'agit de rectangles superposés avec des pixels de décalage, de façon à ce qu'au final on ait des bordures et surtout une surface centrale composée d'un dégradé entre deux bleus. De plus, j'ai ajouté aux coins du cadre les images chargées dans la méthode setup.

J'utilise les méthodes height et width de la classe Gosu::Image pour un positionnement relatif au pixel près.

La méthode suivante étant plus longue, je vais l'exposer en plusieurs fois.

Code:
  def drawMenu
    # boxes
    self.drawBox(0, 0, 160, 224)
    self.drawBox(0, 224, 160, 96)
    self.drawBox(0, 320, 160, 96)
    self.drawBox(0, 416, 160, 64)
    self.drawBox(160, 0, 480, 480)
J'utilise ma méthode drawBox pour créer tous les cadres du menu. On voit ainsi l'utilité d'automatiser la création d'une boite.

Code:
    # menu texts
    @font.draw("Objets", 15, 22, 1)
    @font.draw("Compétences", 15, 54, 1)
    @font.draw("Equiper", 15, 86, 1)
    @font.draw("Etat", 15, 118, 1)
    @font.draw("Sauvegarder", 15, 150, 1)
    @font.draw("Quitter", 15, 182, 1)
Via mon objet @font, je peux facilement créer les textes de mes menus. Z vaut 1 puisque tout le menu est dessiné à Z=0.

Code:
    # stats texts
    if @hours < 10
      hours_display = "0" + @hours.to_s
    else
      hours_display = @hours.to_s
    end
    
    if @minutes < 10
      minutes_display = "0" + @minutes.to_s
    else
      minutes_display = @minutes.to_s
    end

    if @seconds < 10
      seconds_display = "0" + @seconds.to_s
    else
      seconds_display = @seconds.to_s
    end
Ce bout de code ne fait qu'ajouter un zéro devant les unités de temps. C'est plus esthétique qu'autre chose, histoire d'éviter de voir le texte se décaler lorsque par exemple les secondes arrivent à 10.

Code:
    @font.draw("Temps de jeu :", 15, 248, 1, 1, 1, @blue_text)
    @font.draw("#{hours_display}:#{minutes_display}:#{seconds_display}", 160 - @font.text_width("#{hours_display}:#{minutes_display}:#{seconds_display}") - 15, 280, 1)
    @font.draw("Nombre de pas :", 15, 344, 1, 1, 1, @blue_text)
    @font.draw(@steps.to_s, 160 - @font.text_width(@steps.to_s) - 15, 376, 1)
    @font.draw("Or :", 15, 440, 1, 1, 1, @blue_text)
    @font.draw(@gold.to_s, 160 - @font.text_width(@gold.to_s) - 15, 440, 1)
Cette portion de la méthode ne fait qu'afficher les valeurs des variables. Notez que dans certains cas, je me contente du texte et des coordonnées et que dans d'autres je dois ajouter trois arguments (zoom_x, zoom_y et couleur). Ceci s'explique par le fait que la couleur du texte par défaut est le blanc, et que quand je veux avoir une autre couleur je suis contraint de respecter l'ordre des arguments qu'a prévu Gosu et donc spécifier également la dimension du texte.

Notez également que j'utilise la méthode text_width de la classe Gosu::Font, qui retourne la largeur en pixels d'un texte écrit avec la font chargée, ce qui est très pratique pour placer précisément un texte.

Code:
    # characters menu
    cell_x = 164
    cell_y = 3
    next_cell = 117
    @characters.each do |character|
      character.sprite.draw(cell_x + 27, cell_y + 49, 1)
      @font.draw(character.name, cell_x + 78, cell_y + 22, 1)      
      @font.draw(character.job, cell_x + 222, cell_y + 22, 1)    
      @font.draw("Nv", cell_x + 78, cell_y + 54, 1, 1, 1, @blue_text)      
      @font.draw(character.lvl.to_s, cell_x + 122, cell_y + 54, 1)  
      @font.draw("[Normal]", cell_x + 167, cell_y + 54, 1)  
      @font.draw("Exp :", cell_x + 78, cell_y + 84, 1, 1, 1, @blue_text) 
      @font.draw("#{character.exp}/#{character.exp_goal}", cell_x + 173, cell_y + 84, 1)       
      @font.draw("PV", cell_x + 316, cell_y + 54, 1, 1, 1, @blue_text)
      @font.draw("#{character.pv}/#{character.pv_max}", cell_x + 362, cell_y + 54, 1)
      @font.draw("PM", cell_x + 316, cell_y + 84, 1, 1, 1, @blue_text)
      @font.draw("#{character.pm}/#{character.pm_max}", cell_x + 362, cell_y + 84, 1)      
      cell_y += next_cell
    end
Dans cette partie, j'ai codé l'affichage d'une fiche de personnage. Les variables cell_x et cell_y donnent les positions de la première fiche et next_cell la hauteur à descendre pour la suivante.

Ainsi, je peux parcourir le tableau des personnages et donc utiliser le bloc qui constitue l'affichage de la fiche pour chaque personnage, tant que je me décale bien de next_cell pixels vers le bas entre deux personnages.

Le principe est le même que précédemment : afficher du texte, mais aussi afficher l'image du personnage via character.sprite.draw. Cette partie fonctionne du fait des accesseurs que nous avons définis dans la classe Character.

Code:
    # Cursor Drawing
    blue_border = Gosu::Color.new(@cursor_opacity, 192, 224, 255)
    blue1 = Gosu::Color.new(@cursor_opacity, 66, 68, 120)
    blue2 = Gosu::Color.new(@cursor_opacity, 44, 45, 85) 
    
    self.draw_quad(@cursor_x, @cursor_y, blue_border, @cursor_x + 154, @cursor_y, blue_border, 
                          @cursor_x, @cursor_y + 26, blue_border, @cursor_x + 154, @cursor_y + 26, blue_border, 2)
                          
    self.draw_quad(@cursor_x + 1, @cursor_y + 1, blue2, @cursor_x + 153, @cursor_y + 1, blue1, 
                          @cursor_x + 1, @cursor_y + 25, blue2, @cursor_x + 153, @cursor_y + 25, blue1, 2)
    
    @cursor_opacity += 5 if @fading_type == "IN"
    @cursor_opacity -= 5 if @fading_type == "OUT"
    
    @fading_type = "IN" if @cursor_opacity <= 20
    @fading_type = "OUT" if @cursor_opacity >= 160
  end
Enfin, l'affichage du curseur. Il s'agit encore une fois de deux rectangles superposés avec une marge interne de 1 pixel. De plus, les couleurs sont générées dynamiquement pour tenir compte de l'opacité qui évolue à chaque frame.

C'est ici que la variable @fading_type apporte sa pierre à l'édifice : si elle vaut "IN", l'opacité grandit, alors que si elle vaut "OUT", elle diminue. Enfin, on change ce sens lorsque l'extrémité "IN" ou "OUT" est atteinte. Ici, nous voulons que l'opacité varie entre 20 et 160.

Code:
  def updateTimer
    if (Gosu::milliseconds - @last_time) / 1000 == 1
      @seconds += 1
      @last_time = Gosu::milliseconds()
    end
    
    if @seconds > 59
      @seconds = 0
      @minutes += 1
    end
    
    if @minutes > 59
      @hours += 1
      @minutes = 0
    end
  end
Il ne s'agit ici que de calculer le temps écoulé au format heures:minutes:secondes, ce que nous pouvons obtenir grâce à la méthode Gosu::milliseconds(). En stockant le dernier temps écoulé, on peut en déduire quand une seconde est passée, ce qui permet de faire les ajustements nécessaires sur les autres variables de temps.

Code:
  def button_down(id)
    @cursor_y += 32 if id == Gosu::Button::KbDown
    @cursor_y -= 32 if id == Gosu::Button::KbUp
    
    @cursor_y = 19 if @cursor_y > 179
    @cursor_y = 179 if @cursor_y < 19
  end
On s'occupe ici du déplacement du curseur, en faisant en sorte que si le curseur descend plus bas que possible, il remonte tout en haut, et inversement. Nous en faisons ainsi facilement boucler le déplacement.

Code:
  def draw
    self.drawMenu
  end
  
  def update
    self.updateTimer
  end
end
Et enfin, nous définissons nos méthodes draw et update, celles qui je le rappelle constituent dans Gosu la boucle infinie.

A chaque mise à jour (update), le timer est mis à jour. A chaque phase de dessin (draw), le menu est dessiné. Le mot clé self est ici dispensable, je m'en sers uniquement pour mieux repérer sous Scite qu'il s'agit d'un appel de méthode.

Le passage en revue de la classe Window est maintenant terminé. Il suffit de s'en servir.

Code:
win = Window.new
win.addCharacter(Character.new("Arshes", "Combattant", "images/character_01.png"))
win.addCharacter(Character.new("Basil", "Lancier", "images/character_02.png"))
win.addCharacter(Character.new("Gloria", "Prêtre", "images/character_03.png"))
win.addCharacter(Character.new("Hilda", "Mage", "images/character_04.png"))
win.show
On crée d'abord un objet depuis notre classe Window. Ensuite, on crée quatre Characters qu'on ajoute à notre fenêtre via la méthode addCharacter. Pour terminer, un appel à show et la boucle infinie se lance.

Voyez comme il est simple d'utiliser Gosu pour ce genre de programmes. Il existe tant de méthodes destinées à nous simplifier la vie que coder est un véritable plaisir.

Et voici pour terminer le résultat dans une vidéo YouTube :
http://www.youtube.com/watch?v=DwUM7ztw_HI

La capture tourne trop vite, le jeu sinon affiche un temps réel correct

Créer un exécutable standalone :

Ici, on va tout simplement se fixer pour objectif de simplifier la distribution de votre projet Ruby Gosu. En effet, pour que celui-ci soit utilisable par une autre personne, elle doit avoir sur sa machine Ruby et Gosu installés.

Or, tout le monde n'a pas nécessairement installé le langage ou la librairie ou ne souhaite pas forcément le faire pour pouvoir tester votre création.

C'est ici qu'entre en jeu rubyscript2exe. Vous pouvez le télécharger ici :
http://bestguigui.free.fr/tutoriel_g...yscript2exe.rb

Il suffit de mettre ce fichier dans le dossier de votre projet. Ensuite, ouvrez une invite de commandes (démarrer/exécuter/cmd) et rendez-vous dans le dossier de votre projet.

Le fichier qui démarre votre projet doit s'appeler init.rb.

Une fois que vous vous trouvez dans le bon dossier, tapez tout simplement

Code:
ruby rubyscript2exe.rb init.rb
Après quelques messages, qui lanceront d'ailleurs votre programme (le fermer), un fichier init.exe devrait apparaitre. Il s'agit tout simplement d'une compilation de vos fichiers sources, de la distribution de Ruby ainsi que de toutes les librairies utilisées par votre programme.

Tout ce qu'il vous reste à faire, c'est de distribuer ce fichier accompagné de toutes les ressources qui ne sont pas des fichiers sources (images, fichers textes etc.).

L'exécutable sera gros (car il contient bien plus que votre code source), mais il aura au moins l'avantage de permettre à n'importe quel utilisateur de le lancer, sans que les dépendances ne soient requises, pas même Ruby.

Mise à jour 0.7.13 :

Et voilà ! Julian a terminé la mise à jour de la fantastique librairie Gosu. Et des nouveautés, il y en a beaucoup dans cette release, que je vous recommande donc d'installer. Parmi celles-ci :

- Julian a permit d'obtenir la résolution de l'écran qu'utilise le joueur/développeur. Je parle bien de la résolution système, pas de la fenêtre, ce qui peut être utile pour diverses occasions.

- possibilité de savoir si redessiner la fenêtre est utile, afin de gagner en optimisations

- accès au framerate actuel, qu'on peut donc afficher sans avoir à le calculer nous-même

- correction du comportement de la class Gosu::Font avec les caractères accentués, qui s'affichent désormais à merveille, rendant totalement obsolète l'astuce que j'avais proposée précédemment.

- enfin, mise en place définitive de la modification concédée à ma demande : les textures allouées à un espace unique, permettant un texturing à répétition en OpenGL, entre autres choses.

A suivre...
__________________
Réponse avec citation
  #2 (permalink)  
Vieux 17/01/2009, 19h05
Membre
 
Date d'inscription: décembre 2008
Localisation: Strasbourg
Messages: 31
Points Relite: 0.
Donate
Par défaut

J'ai pas encore lu, mais déjà, bravo pour l'initiative!
Réponse avec citation
  #3 (permalink)  
Vieux 17/01/2009, 20h10
Avatar de Dragonsquall
Administrateur
 
Date d'inscription: janvier 2003
Localisation: Melun (77)
Messages: 17 148
Points Relite: 0.
Donate
Entrées dans le blog: 1
Par défaut

Très sympathique l'idée. Merci pour partager cela avec tout le monde. ^^
Réponse avec citation
  #4 (permalink)  
Vieux 17/01/2009, 20h56
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Merci beaucoup

C'est juste que comme j'avais vu sur les commentaires de mes différentes vidéos Youtube, pas mal de monde est intrigué par cette librairie pourtant si facile d'accès ! Quel dommage qu'elle ne soit pas plus sollicitée, d'autant qu'elle est incroyablement performante

Je pense que je mettrai à jour le premier post à chaque avancée, et je compte sur vous pour me donner vos impressions dans les posts suivants de ce topic
__________________
Réponse avec citation
  #5 (permalink)  
Vieux 15/02/2009, 12h38
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Double post pour UP !
J'ai mis à jour le topic en corrigeant quelques éléments et en ajoutant l'étude de la méthode clip_to !

Pensez à bien vérifier que vous utilisez une des dernières versions de Gosu, car cette méthode est très récente

J'ai également ajouté un premier TP : créer un menu type RMXP.
__________________
Réponse avec citation
  #6 (permalink)  
Vieux 08/03/2009, 08h49
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Up ! Si quelqu'un prend la peine de lire le pavé ci-dessus, qui commence à prendre pas mal d'ampleur, des retours me feraient plaisir
__________________
Réponse avec citation
  #7 (permalink)  
Vieux 08/03/2009, 14h35
Avatar de trebor777
Membre
 
Date d'inscription: avril 2006
Localisation: University of Teesside, UK
Messages: 590
Points Relite: 0.
Donate
Envoyer un message via MSN à trebor777
Par défaut

très sympa, vient de comprendre comment on jouer avec l'opacité dans gosu ( commencer à me demander si c t possible xD)

pour faire plus simple dans ta méthode qui ajoute des perso; plutot que de faire

array[array.size-1]
fait
array.last ^^
__________________
"Les bons jeux n'indiquent que la direction que les jeux devrait suivre, les très mauvais vous montrent
le chemin"
Réponse avec citation
  #8 (permalink)  
Vieux 08/03/2009, 16h54
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Yep, c'est sûr, toujours ce bon vieux mauvais réflexe de coder en Ruby avec de sales restes de C

Merci

Julian Raschke est quand même un grand ! Non content d'avoir publié ce tutoriel sur son site officiel, il a modifié la librairie à MA demande dans LA JOURNEE, ce qui m'a permis de créer un loader de .obj qui n'utilise que Ruby Gosu et Ruby OpenGL.

Il a tout simplement corrigé la manière dont les textures sont stockées dans la mémoire, ce qui permet ENFIN de changer les coordonnées de textures, permettant ainsi les répétitions !!

Ce "projet" sera ajouté à Gosu par la suite ! Il sera donc possible de charger un model 3D directement dans n'importe quelle application utilisant Gosu. Me reste pas mal de travail dessus, mais ça fonctionne très bien déjà, à 60 FPS (la limite que j'ai fixé à la fenêtre) pour un texte vectoriel qui consomme beaucoup en polygones.

Vidéo au rendu ignoble ici :
http://www.youtube.com/watch?v=1OdjMUX9PkY

La compression est méchante, car j'ai voulu conserver la fluidité ici, et avec mon PC, je dois choisir l'un ou l'autre

Une capture :


Pour démontrer la fluidité du rendu, je poste même une démo, standalone :
http://bestguigui.free.fr/tutoriel_g..._gosu_demo.rar

Elle n'a besoin de rien pour fonctionner sous Windows. Enjoy
__________________
Réponse avec citation
  #9 (permalink)  
Vieux 15/03/2009, 22h00
Avatar de maeln
Membre
 
Date d'inscription: avril 2007
Localisation: Métropole
Messages: 478
Points Relite: 0.
Donate
Par défaut

J'ai lue la plus grande partit de ton tuto ( tout sauf pour le menu RMXP ) et il est franchement bien fichue . J'ai réussi a afficher du texte , un image et un curseur sur la même fenêtre ( grâce a Z ) . J'aimerais savoir si tu compte continuer car j'aimerais bien savoir comment géré les collisions entre les sprites et comment les déplacer .
Sinon il existe aussi un tutoriel français pour gosu sur developpez.com mais il est trés peu clair et trop difficile a mon niveaux ( d'ailleurs même si ton tutoriel est concentré sur gosu , il ma permit de comprendre certain chose en ruby ) .
Voila , donc un grand merci Guigui .
__________________

Réponse avec citation
  #10 (permalink)  
Vieux 21/03/2009, 01h21
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Citation:
Envoyé par maeln
J'ai lue la plus grande partit de ton tuto ( tout sauf pour le menu RMXP ) et il est franchement bien fichue.
Merci beaucoup, je m'y suis énormément investi et je suis en conséquence content d'avoir contenté quelqu'un avec.

Citation:
Envoyé par maeln
J'ai réussi a afficher du texte , un image et un curseur sur la même fenêtre ( grâce a Z ) . J'aimerais savoir si tu compte continuer car j'aimerais bien savoir comment géré les collisions entre les sprites et comment les déplacer .
On peut envisager cet aspect du moteur comme une seconde réalisation concrète, pourquoi pas. Il faut comprendre néanmoins qu'il ne s'agit pas ici d'une spécificité liée à Gosu, mais bien d'un algo qui puisse être appliqué à toute lib et à tout langage. Je me penche dessus dés que j'ai un moment

Citation:
Envoyé par maeln
Sinon il existe aussi un tutoriel français pour gosu sur developpez.com mais il est trés peu clair et trop difficile a mon niveaux ( d'ailleurs même si ton tutoriel est concentré sur gosu , il ma permit de comprendre certain chose en ruby ) .
Voila , donc un grand merci Guigui .
Je connais très bien ce très bon tutoriel, qui est très condensé et non mis à jour, alors que Gosu est très souvent upgradé. J'ai appris le gros de ce que je sais à base d'analyse des exemples, de gros coups d'oeil à la documentation, et bien entendu à forte concentration de tests en tous genres. Il est si rapide de se lancer une petite fenêtre Scite et de démarrer du code Ruby/Gosu qu'on essaie des centaines de choses en peu de temps. C'est en mon sens un excellent moyen d'apprendre
__________________
Réponse avec citation
  #11 (permalink)  
Vieux 21/03/2009, 23h20
Rédacteur
 
Date d'inscription: décembre 2006
Messages: 313
Points Relite: 0.
Donate
Par défaut

J'ai tout lu.

Citation:
Au passage, lors de la dernière mise à jour de la librairie

[...]

Gosu est une librairie encore très active point de vue développement : son auteur travaille d'arrache pied et ajoute régulièrement bien des fonctionnalités.

[...]

Non content d'avoir publié ce tutoriel sur son site officiel, il a modifié la librairie à MA demande dans LA JOURNEE
Donc, si je comprends bien, le développement de Gosu est très actif ?

J'ai déjà fait tourner RMXP sous RUDL (abandonné depuis 2004), et je voulais le faire tourner sous Rubygame. Mais le projet est maintenant lui aussi abandonné.

Je serais donc assez intéressé pour utiliser Gosu comme librairie pour mes projets d'Editeur 3D pour RM.

______________________

Gosu est sous licence MIT. Cela dit :
Citation:
C'est une licence de logiciel libre et Open Source. Elle donne à toute personne recevant le logiciel le droit illimité de l'utiliser, le copier, le modifier, le fusionner, le publier, le distribuer, le vendre et de changer sa licence. La seule obligation est de mettre le nom des auteurs avec la notice de copyright.
Je peux donc créer un programme propriétaire (changer sa licence) à partir de Gosu ?


Et qu'en est-il de Fmod ?
L'auteur dit "On Linux, if FMOD is not present, SDL_mixer will be used as the default. You use 100% Free code in this case!".
Il y a donc possibilité de ne pas utiliser Fmod ?

Parce que les licences pour Fmod vont de 100 à 6 000 dollars, et ça semble être pour chacune des plateformes sur lesquelles le logiciel est commercialisé...
Donc si possible, je préférerais ne pas avoir à l'utiliser.


Quant à l'usage de la SDL, apparemment, pas de problème :

Citation:
SDL is distributed under GNU LGPL version 2. This license allows you to use SDL freely in commercial programs as long as you link with the dynamic library.
Mais j'aurais voulu être sûr de ce qu'il en est des droits pour un projet commercial fait à partir de Gosu.


______________________


Citation:
Or, tout le monde n'a pas nécessairement installé le langage ou la librairie ou ne souhaite pas forcément le faire pour pouvoir tester votre création.

C'est ici qu'entre en jeu rubyscript2exe.
Je préfère Exerb, car Rubyscript2exe crée un répertoire temporaire sur le PC. Pas toujours effacé en cas de plantage.
Mais malheureusement, pour la création d'un nouveau faiseur d'exécutables en Ruby, personne ne semble vouloir se bouger le *ul.

Pourquoi tant de haine ? Parce que Exerb (et Rubyscript2exe aussi sûrement) crée des programmes tournant en Ruby 1.8.6.


Regardez ce tableau :



Ruby 1.8.6, c'est la barre bleu ciel (en haut).
Ruby 1.9.1, c'est la barre verte (en bas).

Autrement dit, tout programme Ruby distribué sous Windows (en .exe) accuse une lenteur 5 fois et demie supérieure au même programme exécuté à partir de la console de code.

Et ça, c'est sans compter l'obligation de développer en Ruby 1.8.6 au lieu de 1.9.1.
Pour moi qui souhaiterai gérer énormément de fonctions avancées pour le texte, c'est rageant.


Donc ma question :


@ Guigui

Je viens de lire sur le site que l'auteur prévoyait de faire fonctionner les jeux Gosu sur d'autres plateformes que l'ordinateur (Iphone).
Qu'en est-il des exécutables / solutions pour faire tourner Gosu sous Windows sans Ruby ?
A-t-il déjà abordé ce problème ?
Réponse avec citation
  #12 (permalink)  
Vieux 22/03/2009, 17h38
Avatar de trebor777
Membre
 
Date d'inscription: avril 2006
Localisation: University of Teesside, UK
Messages: 590
Points Relite: 0.
Donate
Envoyer un message via MSN à trebor777
Par défaut

AAaatatata qu'est ce que tu racontes comme bêtises King..

1.9.1 tourne sous windows, y'a aucune obligation à utiliser 1.8.6
La seule différence est que pour le moment y'a pas de one click installer 191,(accompagné de plein de librairies pas forcément utile).(C'est en cours, le truc c'est que les libs que le type veut mettre dans oci, sont pas encore toutes compatible 191....donc il doit les modifiers/récup ce qui prend du temps)
Mais t'as les binaires de bases dispo sur le site de ruby. Qui te fournit une installation clean qui tourne. Le seul truc, c'est que tu devras créer toi même tes variables d'environnement path, et rubyopt comme le fait OCI.

à ce que je sache gosu tourne très bien sous 191, et rubyscript2exe aussi. 8)
:roll:
Donc vala
__________________
"Les bons jeux n'indiquent que la direction que les jeux devrait suivre, les très mauvais vous montrent
le chemin"
Réponse avec citation
  #13 (permalink)  
Vieux 23/03/2009, 11h17
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Je n'ai noté aucune différence de performances entre mes versions .rb et .exe. Toutes les personnes qui ont essayé mes démos n'ont pas non plus vu de soucis niveau fluidité/framerate, ou de lenteur d'exécution.

Pour la partie "libre", je n'y connais rien car la perspective de vendre de l'amateur n'a jamais été mienne et ça ne changera pas.

Concernant Ruby, je reste pour l'instant sur ma bonne vieille version 1.8.6, car contrairement aux rubyistes chevronnés, j'ai besoin du one-click-installer.

Concernant RubyScript2exe, je n'ai jamais eu de plantage ni de perte (visible) de mémoire. Je suis totalement satisfait de ce script qui me permet en une minuscule ligne de construire un exécutable standalone.

J'ignore si l'auteur prévoit un autre moyen de distribution, mais il présente RubyScript2exe sur son site, donc je suppose que non.
__________________
Réponse avec citation
  #14 (permalink)  
Vieux 24/03/2009, 12h05
Rédacteur
 
Date d'inscription: décembre 2006
Messages: 313
Points Relite: 0.
Donate
Par défaut

Citation:
Je n'ai noté aucune différence de performances entre mes versions .rb et .exe. Toutes les personnes qui ont essayé mes démos n'ont pas non plus vu de soucis niveau fluidité/framerate, ou de lenteur d'exécution.

Concernant Ruby, je reste pour l'instant sur ma bonne vieille version 1.8.6, car contrairement aux rubyistes chevronnés, j'ai besoin du one-click-installer.
Les deux tournent en 1.8.6.

Par contre, si tu compares sur ruby-doc.org tu verras que des fonctions de base assez chouettes ont été ajoutées depuis ruby 1.8.6.
La méthode insert pour un tableau par exemple. On passe de 81 à 92 méthodes pour la classe Array, et il y en a des sacrément utiles.

C'est à peu près pareil pour toutes les classes.


______

Dommage que l'auteur ne travaille pas sur un compilateur. :\
Enfin, je suppose que les résultats sont déjà satisafaisant en 1.8.6.

Y a-t-il déjà des jeux ou des démos utilisant Gosu ?
Je suppose que oui.


Que conseilles-tu comme démo graphique, et comme démo pour servir de base au code ?
Réponse avec citation
  #15 (permalink)  
Vieux 25/03/2009, 00h49
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Une des dernières démos que j'ai apprécié, bien qu'il ne s'agisse que d'une vidéo Youtube, c'est celle-ci :

http://www.youtube.com/watch?v=FdNFJ5pO14g

Sinon, tu peux trouver des démos sur le forum officiel de Gosu, mais il est vrai que peu pour le moment ne se sont osés au développement sérieux dessus. Je n'ai pas spécialement non plus cherché de démos pour tout dire, plutôt des sources pour apprendre à développer moi-même
__________________
Réponse avec citation
  #16 (permalink)  
Vieux 19/04/2009, 15h44
Avatar de berka
Membre
 
Date d'inscription: décembre 2007
Localisation: dans la peau d'un chara
Messages: 12
Points Relite: 0.
Donate
Par défaut

Très bon tuto qui m'a beaucoup servi !
Juste une question.

J'aimerai initialiser la fenetre et l'afficher, sans pour autant entrer dans la boucle show de Gosu::Window.
Connaitrais tu un moyen d'appeler les meths Window#draw et Window#update de facon externe, sans boucle de mise a jour ?

amicalement,
berka
__________________
.: Je code, donc je suis :.

Rpgruby
Réponse avec citation
  #17 (permalink)  
Vieux 20/04/2009, 07h06
Avatar de Guigui
Membre
 
Date d'inscription: avril 2007
Messages: 388
Points Relite: 0.
Donate
Par défaut

Malheureusement, non, ce n'est pas prévu ainsi. Cela dit, c'est tout à fait contournable

Je l'ai d'ailleurs fait cette nuit même dans un projet où je souhaitais une main-mise totale sur le déroulé de la boucle infinie.

Pour ce faire, j'ai tout simplement crée deux classes majeures :
- la classique classe Window, qui se contente de créer le contexte de fenêtre propre à Gosu et à me retourner les diverses entrées clavier/souris
- la nouvelle classe Engine, qui dispose en son arsenal de variables d'un objet de type fenêtre justement.

Anfin de m'assurer que cela était possible, j'ai tout simplement demandé dans ma classe Window, héritée de Gosu::Window donc, que la méthode udpate appelle la méthode update de ma classe Engine

Petit tour de passe-passe malin qui a bien porté ses fruits. La dernière méthode appelée en effet dans le constructeur de ma classe Engine est bien @window.show, qui permet d'avoir le lancement effectif de la fenêtre, et par-là même des méthodes update et draw de la fenêtre, méthode update qui je le rappelle donc appelle ma méthode update de ma classe Engine, qui fait bien plus que d'afficher quelque chose.

J'utilise donc ainsi la classe Window pour des besoins très restreints et je peux apporter de la modularité à mon code, dont on a tant besoin quand ce dernier devient bien fourni
__________________
Réponse avec citation
  #18 (permalink)  
Vieux 20/04/2009, 08h01
Avatar de berka
Membre
 
Date d'inscription: décembre 2007
Localisation: dans la peau d'un chara
Messages: 12
Points Relite: 0.
Donate
Par défaut

Merci pour la reponse.
En gros je voudrais éviter de devoir mettre tous mes objets graphiques dans la def draw et ne pas bloquer mon programme par la boucle show.

Mais j'ai regardé un peu le code source, et je crois que je vais modifier un peu la def show

Je te tiens au courant,
berka
__________________
.: Je code, donc je suis :.

Rpgruby
Réponse avec citation
  #19 (permalink)  
Vieux 03/05/2009, 19h15
Avatar de maeln
Membre
 
Date d'inscription: avril 2007
Localisation: Métropole
Messages: 478
Points Relite: 0.
Donate
Par défaut

Pour faire bouger un sprite il vas en fait falloir que quand telle touche est presser on modifie la variable de position mais quelle est telle ? il y a sa :
Code:
Class Gosu ::Image def initialize(window, filename_or_rmagick_image, hard_borders, [srcX, srcY, srcWidth, srcHeight])
Donc c'est srcX et srcY qu'il faut modifier ?
Ou alors il faut modifier les valeurs qui se situe ici ? :
Code:
 def draw
	  @sprite.draw(320, 240, 1) #affichage du sprite 
  end
Et la c'est la même quéstion : quelle est le nom des variables qui sont ici (320, 240, 1) ?
Réponse avec citation
  #20 (permalink)  
Vieux 23/05/2009, 17h09
Avatar de berka
Membre
 
Date d'inscription: décembre 2007
Localisation: dans la peau d'un chara
Messages: 12
Points Relite: 0.
Donate
Par défaut

dans ton cas il faut modifier les valeurs de la méthode draw:

Code:
@img.draw(x,y,z)
x=> i/f abscisses, origine: gauche
y=> i/f ordonnées, origine: haut
z=> i/f superposition

berka
__________________
.: Je code, donc je suis :.

Rpgruby
Réponse avec citation
Réponse

Outils de la discussion
Modes d'affichage

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui
Navigation rapide

LinkBacks (?)
LinkBack to this Thread: http://forum.relite.org/tutoriaux-logiciels-de-creation/3393-ruby-gosu-cours-complet.html
Envoyé par For Type Date
Forum Du Référencement a Marseille • Ruby fait tout ! This thread Refback 06/05/2010 20h27
Forum Du Référencement a Marseille • Ruby fait tout ! This thread Refback 03/02/2010 12h58
[ruby] librairie graphique gosu This thread Refback 26/01/2010 10h56

Discussions similaires
Discussion Auteur Forum Réponses Dernier message
[Cours]Ruby/RGSS Drakhaine Astuces programmation 11 10/06/2007 21h49
[Ruby] Hackety Hack: apprenez le ruby sans effort youpi Astuces programmation 24 09/05/2007 05h05
[Recrutement] Projet kh en cours ichigo95 Petites annonces 25 15/10/2006 15h42
[Ruby Gosu/OpenGL] Moteur 2.5D Akres Vos projets de jeux vidéo (WIP) 0 02/01/1970 05h33
[Cours]Ruby/RGSS Godof Realisations 3 01/01/1970 23h22


Fuseau horaire GMT +2. Il est actuellement 13h08.
Relite© 2002-2009 - Edité par Relite Network
Les forums Relite sont des forums de discussion dédiés aux jeux vidéo indépendants, jeux vidéo amateurs et en rapport avec le développement et création de ces mêmes jeux vidéo.