Partage
  • Partager sur Facebook
  • Partager sur Twitter

ruby - Partie 2 Activité

Et si on créait un petit jeu ?

    23 avril 2018 à 11:34:08

    Bonjour à tous :)

    je suis depuis plusieurs jours bloqué sur la création du jeu ...

    En fait le programme plante lorsque les ennemis attaquent le joueur avec une variable Nil :

    LES ENNEMIS RIPOSTENT !
    Balrog attaque Jean-Michel Paladin
    Jean-Michel Paladin Inflige 41 points de dégats !
    jeu.rb:28:in `-': nil can't be coerced into Integer (TypeError)
            from jeu.rb:28:in `subit_attaque'
            from jeu.rb:20:in `attaque'
            from jeu.rb:177:in `block (2 levels) in <main>'
            from jeu.rb:175:in `each'
            from jeu.rb:175:in `block in <main>'
            from jeu.rb:146:in `times'
            from jeu.rb:146:in `<main>'

    J'ai beau relire je ne comprend pas pourquoi elle est nulle ... J'ai mis des points de surveillance et en effet je perd sa valeur c'est louche !

    Si quelqu'un à une idée je suis preneur ! Le code entier pour aider :

    class Personne
      attr_accessor :nom, :points_de_vie, :en_vie
    
      def initialize(nom)
        @nom = nom
        @points_de_vie = 100
        @en_vie = true
      end
    
      def info
        if @en_vie == true
          puts @nom + "il reste #{points_de_vie}/100"
        else
          puts nom + " (Vaincu)"
        end
      end
    
      def attaque(personne)
        puts nom + " attaque #{personne.nom}"
        personne.subit_attaque(degats)
        # A faire:
        # - Fait subir des dégats à la personne passée en paramètre
        # - Affiche ce qu'il s'est passé
      end
    
      def subit_attaque(degats_recus)
        degats_recus = degats
        @points_de_vie -= degats_recus
    
        puts "\n#{nom} a subi #{degats_recus} de dégats, il lui reste #{points_de_vie} points de vie.\n"
        @en_vie == false if @points_de_vie <= 0
        # A faire:
        # - Réduit les points de vie en fonction des dégats reçus
        # - Affiche ce qu'il s'est passé
        # - Détermine si la personne est toujours en_vie ou non
      end
    end
    
    class Joueur < Personne
      attr_accessor :degats_bonus
    
      def initialize(nom)
        # Par défaut le joueur n'a pas de dégats bonus
        @degats_bonus = 0
    
        # Appelle le "initialize" de la classe mère (Personne)
        super(nom)
      end
    
      def degats
        degats = rand(25..45) + degats_bonus
        puts nom + " Inflige #{degats} points de dégats !"
        # A faire:
        # - Calculer les dégats
        # - Affiche ce qu'il s'est passé
      end
    
      def soin
        if @points_de_vie < 100
          @points_de_vie += 10
          puts "Vous avez gagné 10 points de vie."
        else
          puts "Vous avez déjà 100 points de vie."
        end
        # A faire:
        # - Gagner de la vie
        # - Affiche ce qu'il s'est passé
      end
    
      def ameliorer_degats
        @degats_bonus += rand(10..45)
        puts "Vous avez gagné #{@degats_bonus} points de dégat."
        # A faire:
        # - Augmenter les dégats bonus
        # - Affiche ce qu'il s'est passé
      end
    end
    
    class Ennemi < Personne
      def degats
        degats = rand(25)
        # A faire:
        # - Calculer les dégats
      end
    end
    
    class Jeu
      def self.actions_possibles(monde)
        puts "ACTIONS POSSIBLES :"
    
        puts "0 - Se soigner"
        puts "1 - Améliorer son attaque"
    
        # On commence à 2 car 0 et 1 sont réservés pour les actions
        # de soin et d'amélioration d'attaque
        i = 2
        monde.ennemis.each do |ennemi|
          puts "#{i} - Attaquer #{ennemi.info}"
          i = i + 1
        end
        puts "99 - Quitter"
      end
    
      def self.est_fini(joueur, monde)
        # A faire:
        # - Déterminer la condition de fin du jeu
      end
    end
    
    class Monde
      attr_accessor :ennemis
    
      def ennemis_en_vie
        # un tableau pour stocker les ennemis en vie
        qui_sont_en_vie = []
    
        # on boucle sur le tableau des ennemis
        @ennemis.each do |ennemi|
        # on insère dans le tableau si l'ennemi est en vie
          qui_sont_en_vie << ennemi if ennemi.en_vie
        end
        # on renvoie le tableau
        qui_sont_en_vie
      end
    end
    
    ##############
    
    # Initialisation du monde
    monde = Monde.new
    
    # Ajout des ennemis
    monde.ennemis = [
      Ennemi.new("Balrog"),
      Ennemi.new("Goblin"),
      Ennemi.new("Squelette")
    ]
    
    # Initialisation du joueur
    joueur = Joueur.new("Jean-Michel Paladin")
    
    # Message d'introduction. \n signifie "retour à la ligne"
    puts "\n\nAinsi débutent les aventures de #{joueur.nom}\n\n"
    
    # Boucle de jeu principale
    100.times do |tour|
      puts "\n------------------ Tour numéro #{tour} ------------------"
    
      # Affiche les différentes actions possibles
      Jeu.actions_possibles(monde)
    
      puts "\nQUELLE ACTION FAIRE ?"
      # On range dans la variable "choix" ce que l'utilisateur renseigne
      choix = gets.chomp.to_i
    
      # En fonction du choix on appelle différentes méthodes sur le joueur
      if choix == 0
        joueur.soin
      elsif choix == 1
        joueur.ameliorer_degats
      elsif choix == 99
        # On quitte la boucle de jeu si on a choisi
        # 99 qui veut dire "quitter"
        break
      else
        # Choix - 2 car nous avons commencé à compter à partir de 2
        # car les choix 0 et 1 étaient réservés pour le soin et
        # l'amélioration d'attaque
        ennemi_a_attaquer = monde.ennemis[choix - 2]
        joueur.attaque(ennemi_a_attaquer)
      end
    
      puts "\nLES ENNEMIS RIPOSTENT !"
      # Pour tous les ennemis en vie ...
      monde.ennemis_en_vie.each do |ennemi|
        # ... le héro subit une attaque.
        ennemi.attaque(joueur)
      end
    
      puts "\nEtat du héro: #{joueur.info}\n"
    
      # Si le jeu est fini, on interompt la boucle
      break if Jeu.est_fini(joueur, monde)
    end
    
    puts "\nGame Over!\n"
    
    # A faire:
    # - Afficher le résultat de la partie
    
    if joueur.en_vie
      puts "Vous avez gagné !"
    else
      puts "Vous avez perdu !"
    end
    

    En vous remmerciant :)


    • Partager sur Facebook
    • Partager sur Twitter
      23 avril 2018 à 12:12:19

      Salut,

      À ta ligne 27, tu donnes une valeur à degats_recus, quelle est cette valeur ? C’est ce qui pose problème.

      Sinon, d’autres remarques.

      • À quoi ça te sert d’avoir une variable pour savoir si une personne est en vie et une autre pour son nombre de points de vie ? Autant faire une méthode pour savoir si la personne est en vie (elle consisterait juste à renvoyer pv &gt; 0.
      • Pour connaître les ennemis en vie, tu peux utiliser select.
      • Ta fonction de soin permet d’avoir plus de 100 points de vie, c’est voulu ?
      • Une méthode to_s serait préférable à infos. Ça permettrait d’écrire print joueur plutôt que print joueur.info.
      • Certaines données devraient être accessibles en lecture seulement (attr_reader) et pas en écriture. Par exemple, on ne veut pas pouvoir modifier le nom d’une personne. degats_bonus, lui, n’a même pas à être accessible.
      • Partager sur Facebook
      • Partager sur Twitter
      Tutoriel Ruby - Bon tutoriel C - Tutoriel SDL 2 - Python avancé - Faîtes un zeste, devenez des zesteurs
        24 avril 2018 à 10:16:23

        Bonjour yo@n97one,

        Merci beaucoup pour ton retour :)

        en fait la valeur que je lui attribut c'est les dégâts soit infligés par le monstre soit par le joueur c'est pour cela que j'ai un = degats

        en fait je pense que si tu ne l'as pas vu c'est que je transite mal l'information ... Faut que je me fasse un schéma pour y voir plus clair !

        tu parles de info ? Parce que la consigne est de renvoyer "en vie" si la personne est en voe et ses points de vie ou dire "vaincu", mais oui dans la pratique c'es plus une méthode j'admet :)

        Je vais retravailler tout ça et trouver ou ça coince sur les dégâts !

        • Partager sur Facebook
        • Partager sur Twitter
          24 avril 2018 à 11:31:12

          Non, c’est pas que je ne l’ai pas vu, c’est que c’est exactement cette affectation qui cause ton erreur puisque degats vaut nil. En fait, ici, tu passes les dégâts à infliger à ta méthode subit_attaque dans attaque à la ligne 20, degats_recus vaut donc cette valeur puisque c’est le paramètre de ta méthode subit_attaque. Je pense donc que tu as mal compris comment se passe le passage des arguments à une fonction.

          Je ne comprends pas ce que tu veux dire à propos de info. info est une méthode dans ton code (pas seulement dans la pratique), c’est une méthode de la classe Personne. Mon propos était juste que plutôt que de définir cette méthode pour faire print joueur.info, ce serait beaucoup mieux de définir to_s pour pouvoir faire print joueur (en fait, j’ai presque envie de dire que c’est une mauvaise pratique de définir info comme ça).

          • Partager sur Facebook
          • Partager sur Twitter
          Tutoriel Ruby - Bon tutoriel C - Tutoriel SDL 2 - Python avancé - Faîtes un zeste, devenez des zesteurs
            29 décembre 2019 à 14:06:50

            J'ai aussi le même problème que la plupart des gens, et je pense bien que la majorité des gens ont compris que la valeur était nil, ce que je ne comprends pas c'est comment attribuer cette valeur ? Comment la récupérer ?

            Cette réponse que je vois partout n'aide pas beaucoup malheureusement.

            • Partager sur Facebook
            • Partager sur Twitter
              29 décembre 2019 à 14:15:45

              Montre ton code, sans lui difficile de t’aider.

              • Partager sur Facebook
              • Partager sur Twitter
              Tutoriel Ruby - Bon tutoriel C - Tutoriel SDL 2 - Python avancé - Faîtes un zeste, devenez des zesteurs
                29 décembre 2019 à 14:36:32

                Mon erreur est exactement la même que celle ci, à la ligne 27-28.

                -
                Edité par Brainnos 29 décembre 2019 à 14:44:33

                • Partager sur Facebook
                • Partager sur Twitter
                  29 décembre 2019 à 18:10:43

                  Oui, mais deux codes différents peuvent mener à exactement la même erreur. En tout cas, l'erreur est due à une mauvaise compréhension de la portée des variables. Le tutoriel d'OC semble décidément mal expliquer cela vu... Tu peux regarder ici (et en fait regarder le reste du tutoriel si besoin vu que j'ai l'impression que la transmission des arguments est également mal expliquée).

                  En particulier, le problème c'est qu'on a voulu nommer une méthode et une variable de la même manière. Mais la variable degats de la méthode degats est locale à la méthode degats. Quand degats est utilisée dans les méthodes attaque ou subit_attaque, c'est la méthode qui est appelée, et cette méthode renvoie nil. Et on sent le problème... En fait, pourquoi une méthode degats devrait afficher ce qu'il s'est passé. La méthode degats devrait juste renvoyer le nombre de dégats.

                  def attaquer(personne)
                    puts "#{nom} attaque #{personne.nom}"
                    personne.subir_degats(degats)
                  end
                  
                  def subir_degats(degas_recus)
                    @points_de_vie -= degats_recus # En fait, vérifier que points de vie reste positif
                    # Autres trucs
                  end
                  
                  def degats # On retourne un nombre
                    rand(10..25)
                  end
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Tutoriel Ruby - Bon tutoriel C - Tutoriel SDL 2 - Python avancé - Faîtes un zeste, devenez des zesteurs

                  ruby - Partie 2 Activité

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown