RPG Creator : créez votre MMORPG ou RPG sans aucune connaissance en programmation


Disponible le 4 Juin !




- Jouez à votre jeu sur tablettes tactiles, Smartphones et navigateurs Web
- Personnalisez vos menus
- Dessinez facilement et rapidement vos cartes
- Créez des actions pour le combat A-RPG


www.rpgcreator.net


Heures au format UTC + 1 heure [ Heure d’été ]




Publier un nouveau sujet Répondre au sujet  [ 6 messages ] 
Auteur Message
 Sujet du message: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:52 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]
Concevoir et réaliser son systême sur RMXP


Les modérateurs sont libres de déplacer ce tutorial là où il semblera le plus approprié, dans la section Tuto, Tuto avancé ou Ruby.

[]Sommaire

I) Le modèle à 3 couches
II) La couche de données statiques
III) La couche de données dynamiques
IV) La couche de représentation graphique
V) Conclusion


Haut
 Profil  
 
 Sujet du message: Re: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:52 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]I) Le modèle à 3 couches

Trop souvent, on peut voir des scripts RMXP proposant des systèmes où tous les composants sont tellement imbriqués les uns les autres qu'il devient impossible de modifier quoique ce soit.
Ce que je propose ici est un modèle de développement en 3 couches qui respecte au maximum la manière de procéder dans RMXP, en donnant un maximum d'indépendance à tous ces composants.

Les 3 couches sont :
[list]
- une couche de données statiques constituée par la base de données.

- une couche de données dynamiques qui utilisent les données statiques pour l'initialisation, et qui évolue selon la logique propre au système.

- une couche de représentation graphique du système.
[/list:u]

Un exemple concret tiré de RMXP pour mieux visualiser les 3 couches est la gestion des différents héros :
[list]
- La 1ère couche des données statiques est créée grâce à l'interface de la base de données de RMXP dans l'onglet "Héros". Pour chaque héro est créé un objet RPG::Actor qui contient les données d'initialisation du héro, et qui sera ensuite stocké dans le fichier Data/Actors.rxdata. Ce fichier est ensuite chargé à l'écran titre par
Code: Tout sélectionner
$data_actors = load_data("Data/Actors.rxdata")


- La 2ème couche est illustrée principalement par les classes Game_Actor qui modélise les héros avec des stats et un équipement qui évoluent au cours du temps et qui possède les fonctionnalités pour manipuler ces stats, Game_Actors qui représente l'ensemble des héros disponibles et Game_Party qui permet de gérer quels héros se trouvent actuellement dans l'équipe.
Observons comment un Game_Actor s'initialise à partir de son identifiant dans la base de données : on commence tout d'abord par récupérer l'objet RPG::Actor correspondant par
Code: Tout sélectionner
actor = $data_actors[actor_id]

puis on utilise cet objet pour initialiser les données du Game_Actor.

- La 3ème couche est représenté par toutes les scènes du menu de base. Scene_Status donne un aperçu global des stats et de l'équipement d'un objet Game_Actor, Scene_Skills permet de voir et d'utiliser ses techniques, et Scene_Equip permet de manipuler son équipement en se servant des fonctionnalités de l'objet.
[/list:u]

Nous allons nous servir de ce modèle en 3 couches pour concevoir et créer un système de quêtes basique, ayant les caractéristiques suivantes :
[list]
- Une quête a un nom, une description, et rapporte une fois accomplie une somme d'argent et de l'expérience au groupe.

- Le groupe reçoit des quêtes. On doit pouvoir faire la distinction entre une quête en cours et terminée.

- Par dessus ce système, on créera une Scene qui permettra d'avoir la liste des quêtes en cours et terminées, ainsi que leurs caractéristiques.
[/list:u]


Haut
 Profil  
 
 Sujet du message: Re: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:53 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]II) La couche de données statiques

On crée tout d'abord un nouvelle classe pour la base de données qui va permettre de stocker les données des quêtes.
Code: Tout sélectionner
class RPG::Quest
   
  def initialize
    @id = 0
    @name = ""
    @description = ""
    @gold = 0
    @exp = 0
  end

  attr_accessor :id
  attr_accessor :name
  attr_accessor :description
  attr_accessor :gold
  attr_accessor :exp

end


Le problème, c'est que contrairement à la base de données de base, il n'existe pas d'interface graphique pour créer et gérer la base de données des quêtes.

Une solution souvent adoptée et pourtant horrible conceptuellement, est de coder la base de données en Ruby à l'intérieur des scripts.
[list]
- Cela oblige ceux qui réalisent la base de données à apprendre les rudiments du Ruby.

- On se retrouve avec une trop grande imbrication des composants, ce qui rend plus difficile le travail en équipe : il va y avoir un décalage problématique entre l'état des scripts du scripteur, sans la base de données, et celui du chef d'équipe qui contient la base de données ; à chaque fois que le scripteur donne son Scripts.rxdata, le chef de projet devra faire attention à ne pas supprimer sa base de données en remplaçant son fichier Scripts.rxdata.
[/list:u]

Une solution beaucoup plus propre est de fournir une interface pour celui qui réalise la base de données, mais pas nécessairement une interface graphique. Utiliser des fichiers texte par exemple est une bonne alternative. Voyons ce que cela peut donner dans notre système de quêtes.

A la racine du jeu, on créera un nouveau dossier "Quests Data" qui contiendra des fichiers texte de la forme :
Citer:
id : <un nombre>
name : <un nom>
description : <une description>
gold : <une somme d'argent>
exp : <une quantité d'expérience>


A partir de ses fichiers texte, on va créer des objets RPG::Quest qui seront stockés dans le fichier Data/Quests.rxdata. Au moment de crypter le jeu, il ne restera plus qu'à enlever le dossier "Quests Data", et seul le fichier Data/Quests.rxdata sera crypté avec le jeu, gardant ainsi secret la base de données de quêtes.

Voyons comment coder cela :
Code: Tout sélectionner
class Scene_Title

  alias quest_main main
  def main
    # Au début de l'écran titre
    # si le jeu n'est pas crypté
    if $DEBUG
      # on crée le dossier "Quests Data" si il n'existe pas déjà
      begin
        Dir.mkdir("Quests Data")
      rescue
      end
      # on crée le fichier Data/Quests.rxdata
      create_quests_rxdata
    end
    # on charge la base de données des quêtes
    $data_quests = load_data("Data/Quests.rxdata")
    # on execute le reste de l'écran titre
    quest_main
  end

  # Méthode de création du fichier Data/Quests.rxdata
  def create_quests_rxdata
    # Le tableau qui contiendra les objets RPG::Quest
    quests_data = []
    # Pour chaque fichier texte dans le dossier "Quests Data"
    for file_name in Dir["Quests Data/*.txt"]
      # on crée un nouvel objet RPG::Quest
      quest = RPG::Quest.new
      # on ouvre le fichier en mode lecture
      File.open(file_name, 'r') do |txt_file|
        # on initialise les propriétés de la quête
        # en lisant le fichier ligne par ligne
        # (pour plus de compréhension,
        # regarder les méthodes des classes File et String)
        quest.id = txt_file.readline.gsub("id : ", "").to_i
        quest.name = txt_file.readline.gsub("name : ", "").to_s
        quest.description = txt_file.readline.gsub("description : ", "").to_s
        quest.gold = txt_file.readline.gsub("gold : ", "").to_i
        quest.exp = txt_file.readline.gsub("exp : ", "").to_i
      end
      # on stocke l'objet RPG::Quest à son index dans le tableau
      quests_data[quest.id] = quest
    end
    # On ouvre le fichier Data/Quests.rxdata en mode écriture binaire
    File.open("Data/Quests.rxdata", 'wb') do |rxdata_file|
      # on stocke le tableau des quêtes dans le fichier Data/Quests.rxdata
      Marshal.dump(quests_data, rxdata_file)
    end
  end

end


Haut
 Profil  
 
 Sujet du message: Re: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:53 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]III) La couche de données dynamiques

On crée tout d'abord une classe Game_Quest qui va servir à modéliser une quête qui s'initialise avec les données d'un objet RPG::Quest, et qui au départ n'est pas terminée. Il faut aussi une méthode pour savoir si elle est terminée et une méthode qui permet de terminer la quête et de donner l'argent et l'expérience.

Code: Tout sélectionner
class Game_Quest
 
  attr_reader :id
  attr_reader :name
  attr_reader :description
  attr_reader :gold
  attr_reader :exp
 
  def initialize(quest_id)
    # On récupère tout d'abord l'objet RPG::Quest pour l'initialisation
    quest = $data_quests[quest_id]
     # et on initialise les données
    @id = quest.id
    @name = quest.name
    @description = quest.description
    @gold = quest.gold
    @exp = quest.exp
    # La quête n'est pas terminée au départ
    @finished = false
  end
 
  # Méthode qui renvoie si la quête est terminée ou non
  def finished?
    return @finished
  end
 
  # Méthode qui permet de terminer la quête
  def finish
    # La quête est terminée
    @finished = true
    # Le groupe gagne de l'argent   
    $game_party.gain_gold(@gold)
    # Les membres du groupe gagnent de l'expérience
    for actor in $game_party.actors
      actor.exp += @exp
    end
  end
 
end


Il reste maintenant à rajouter à la classe Game_Party de quoi recevoir et finir des quêtes.
Code: Tout sélectionner
class Game_Party
 
  attr_reader :quests
 
  # On rajoute dans Game_Party un tableau qui contient les quêtes reçus
  alias quest_initialize initialize
  def initialize
    quest_initialize
    @quests = []
  end
 
  # Méthode qui pemet de recevoir une quête
  def get_quest(quest_id)
    # On ajoute à la liste des quêtes un nouvel objet Game_Quest
    @quests << Game_Quest.new(quest_id)
  end
 
  # Méthode qui permet de finir une quête
  def finish_quest(quest_id)
    # On récupère une quête d'id quest_id qui n'est pas terminée
    quest = @quests.find { |quest|
      quest.id == quest_id and not quest.finished?
    }
    # Si une telle quête existe, on la termine
    quest.finish if quest != nil
  end
 
end


Pour recevoir une quête d'id quest_id, on utilisera le script
Code: Tout sélectionner
$game_party.get_quest(quest_id)

et pour la terminer ensuite
Code: Tout sélectionner
$game_party.finish_quest(quest_id)


Haut
 Profil  
 
 Sujet du message: Re: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:54 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]IV) La couche de représentation graphique

Il reste maintenant à coder une Scene qui permet de savoir quelles quêtes sont en cours, lesquelles sont terminées, et de pouvoir voir combien d'argent et d'expérience elles rapportent.
Voici un exemple de Scene basique. Le code n'est pas détaillé et compréhensible pour les personnes capables d'écrire leurs propres Scenes. Si vous n'en etes pas capable, allez jeter un oeil sur le tutorial de création de Scenes.

Code: Tout sélectionner
class Scene_Quest
 
  def main
    @command_window = Window_QuestCommand.new
    @status_window = Window_QuestStatus.new
    @quest_window1 = Window_Quest.new(0)
    @quest_window2 = Window_Quest.new(1)
    @quest_window1.status_window = @status_window
    @quest_window2.status_window = @status_window
    refresh
    Graphics.transition
    loop do
      Graphics.update
      Input.update
      update
      if $scene != self
        break
      end
    end
    Graphics.freeze
    @command_window.dispose
    @status_window.dispose
    @quest_window1.dispose
    @quest_window2.dispose
  end
 
  def refresh
    @quest_window1.visible = (@command_window.index == 0)
    @quest_window2.visible = (@command_window.index == 1)
    case @command_window.index
    when 0
      @quest_window = @quest_window1
    when 1
      @quest_window = @quest_window2
    end
  end
 
  def update
    @command_window.update
    @status_window.update
    @quest_window.update
    refresh
    if @command_window.active
      update_command
      return
    end
    if @quest_window.active
      update_quest
      return
    end
  end
 
  def update_command
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      return
    end
    if Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      @command_window.active = false
      @quest_window.index = 0
      @quest_window.active = true
      return
    end
  end
 
  def update_quest
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @quest_window.active = false
      @quest_window.index = -1
      @command_window.active = true
      return
    end
  end
 
end

class Window_QuestCommand < Window_Selectable
 
  def initialize
    super(0, 0, 640, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.contents.font.name = $fontface
    self.contents.font.size = 24
    self.back_opacity = 160
    @commands = ["En cours", "Terminées"]
    @item_max = 2
    @column_max = 2
    draw_item(0)
    draw_item(1)
    self.index = 0
  end
 
  def draw_item(index)
    rect = Rect.new(160 + index * 160 + 4, 0, 128 - 10, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    self.contents.draw_text(rect, @commands[index], 1)
  end
 
  def update_cursor_rect
    self.cursor_rect.set(160 + index * 160, 0, 128, 32)
  end
 
end

class Window_Quest < Window_Selectable
 
  attr_writer :status_window
 
  def initialize(quest_status)
    super(0, 256, 640, 224)
    @quest_status = quest_status
    @column_max = 2
    refresh
    self.active = false
    self.index = -1
  end
 
  def quest
    return self.index == -1 ? nil : @data[self.index]
  end
 
  def update
    @status_window.quest = self.quest
  end
 
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    if @quest_status == 0
      @data = $game_party.quests.find_all { |quest|
        not quest.finished?
      }
    end
    if @quest_status != 0
      @data = $game_party.quests.find_all { |quest|
        quest.finished?
      }
    end
    @item_max = @data.size
    self.contents = Bitmap.new(width - 32, height - 32)
    self.contents.font.name = $fontface
    self.contents.font.size = $fontsize
    for i in 0...@item_max
      draw_quest(i)
    end
  end
 
  def draw_quest(index)
    quest = @data[index]
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    self.contents.draw_text(x , y, 280, 32, quest.name, 0)
  end
 
end

class Window_QuestStatus < Window_Base
 
  def initialize
    super(0, 64, 640, 192)
    self.contents = Bitmap.new(width - 32, height - 32)
    self.contents.font.name = $fontface
    self.contents.font.size = $fontsize
    @old_quest = nil
  end
 
  def quest=(quest)
    @quest = quest
    refresh
  end
 
  def refresh
    if @quest != @old_quest
      self.contents.clear
      @old_quest = @quest
      if @old_quest != nil
        self.contents.draw_text(0, 0, 600, 32, @old_quest.description)
        self.contents.draw_text(0, 60, 600, 32, "Argent : #{@old_quest.gold}")
        self.contents.draw_text(0, 120, 600, 32, "Exp : #{@old_quest.exp}")
      end
    end
  end
     
end


Pour appeler la Scene, un simple
Code: Tout sélectionner
$scene = Scene_Quest.new

fera l'affaire.


Haut
 Profil  
 
 Sujet du message: Re: [Tutorial Ruby] Concevoir et réaliser son systême sur RMXP
MessagePublié: 14 Sep 2007, 18:54 
Ancien membre du staff
Ancien membre du staff
Avatar de l’utilisateur

Inscrit le: 12 Aoû 2006, 00:00
Messages: 1064
Points d'aide: 5/60

Créations :

- [RMXP] Database Management

- [RMXP] GUI Widgets

- [RMXP] Advanced Input


Voir ses créations

[]V) Conclusion

Le modèle présentée ici peut être appliqué à tout type de système nécessitant une base de données derrière. Les manières de coder présentées sont aussi assez génériques et peuvent être appliquées dans bon nombre de situation.

On pourra plus tard constater un certain systématisme dans les techniques de codage, ce qui me fait penser qu'il va devenir nécessaire de créer diverses librairies pour automatiser certaines tâches, comme par exemple la lecture des fichiers texte et leur transformation en fichiers rxdata.

Si vous éprouvez des difficultés à comprendre le tutorial :
- vous n'avez pas encore le niveau =)
- si vous avez déjà un peu d'expérience mais que vous ne comprennez pas, envoyez moi un MP


Haut
 Profil  
 
Afficher les messages depuis:  Trier par  
Publier un nouveau sujet Répondre au sujet  [ 6 messages ] 

Heures au format UTC + 1 heure [ Heure d’été ]


Qui est en ligne ?

Utilisateurs parcourant actuellement ce forum : Aucun utilisateur inscrit et 3 invités


Vous ne pouvez pas publier de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas insérer de pièces jointes dans ce forum

Rechercher pour:
Sauter vers:  
cron
RPG Creative Forum version 5 ; Tous droits réservés
phpBB Group (Traduit par Xaphos)
Optimisé pour une résolution 1024*728