【问题标题】:Ruby Beginner - Accessing Another Class ObjectRuby 初学者 - 访问另一个类对象
【发布时间】:2014-05-01 13:33:21
【问题描述】:

我正在尝试在 Ruby 中创建一个简单的回合制战斗,但在课程方面我总是卡住。我试图通过从基本代码开始并围绕它构建它来做到这一点。通过使用常规变量和基本攻击代码,我能够使其工作变得足够简单:

player = "goodguy"
player_health = 15
player_damage = 5

enemy = "badguy"
enemy_health = 15
enemy_damage = 5

puts "#{player} attacks #{enemy} and does #{player_damage} damage."
enemy_health -= player_damage
puts "#{enemy} has #{enemy_health} remaining."

然后,我将攻击变成了一个函数(我必须将变量设为全局变量,以便函数可以看到它们):

$player = "goodguy"
$player_health = 15
$player_damage = 5

$enemy = "badguy"
$enemy_health = 15
$enemy_damage = 5

def player_attack
  puts "#{$player} attacks #{$enemy} and does #{$player_damage} damage."
  $enemy_health -= $player_damage
  puts "#{$enemy} has #{$enemy_health} health remaining."
  if $enemy_health <= 0
    puts "#{$enemy} died!"
  end    
end    

player_attack()

接下来,我把Player变成了一个类:

class Player
  attr_accessor :name; :hp; :damage
  def initialize(name, hp, damage)
    @name = name
    @hp = hp
    @damage = damage
  end

  def attack
    puts "#{self.name} attacks #{$enemy}!"
    $enemy_health -= @damage
    puts $enemy_health
  end
end

$enemy = "badguy"
$enemy_health = 15
$enemy_damage = 5    

me = Player.new("goodguy", 15, 5)

me.attack

这就是我卡住的地方。当我将Enemy 变成一个类(基本上完全按照Player 类建模)时,我无法弄清楚如何使这两个对象相互交互。这段代码不起作用,但这是我尝试的最后一个。 #{} 变量更能显示我想要实现的目标:

class Player
  attr_accessor :name; :hp; :damage
  def initialize(name, hp, damage)
    @name = name
    @hp = hp
    @damage = damage
  end

  def attack
    puts "#{self.name} attacks #{badguy.name}!"
    badguy.hp -= @damage
    puts badguy.hp
  end
end

class Enemy
  attr_accessor :name; :hp; :damage
  def initialize(name, hp, damage)
    @name = name
    @hp = hp
    @damage = damage
  end

  def attack
    puts "#{self.name} attacks #{goodguy.name}!"
    player.hp -= @damage
    puts player.hp
  end
end  

goodguy = Player.new("Nicehero", 15, 5)
badguy = Enemy.new("Eviljerk", 15, 5)

me.attack 

基本上,我想做的是让Player 对象可以与Enemy 对象交互。当我尝试让 2 个类相互交互时,我似乎无法正常工作;此外,#{variable.name} 并不是我尝试让函数报告这些值的唯一方法,但我似乎无法找到如何实际引用该对象。

显然,关于对象如何交互或我的代码正在做什么以及我认为它应该做什么,我缺少一些东西。我将不胜感激有关让这两个类进行交互或如何重写它以使其按预期运行的任何建议。

【问题讨论】:

  • 类不会神奇地知道彼此的实例;某些实体必须告诉他们。一种常见的方法是让另一个类代表游戏或棋盘,它负责对玩家说:“轮到你了,这是敌人,这是敌人做了什么,你会做什么? "
  • 谢谢@JacobM,你能举个例子说明如何使用父类来完成吗?

标签: ruby


【解决方案1】:

正如@JacobM 所提到的,您遇到的问题与您的类无法在没有您明确地将它们作为参数传递的情况下了解彼此的其他实例有关。尽管您最初使用 全局变量 来保存对敌人和玩家的引用的解决方法会起作用,但强烈建议不要使用这种做法,因为它会在整个游戏主体中“泄露”程序的逻辑,这通常是不可取的(请参阅 Global Variables are Bad 了解为什么要避免它们的详细说明)。

通过从代码中删除 $playerattack 方法中定义时成为局部变量:

def attack
  puts "#{self.name} attacks #{goodguy.name}!"
  player.hp -= @damage
  puts player.hp
end

在此构造中,您希望作为Player 类的实例引用的player 变量实际上是您在方法主体中声明的未定义局部变量。因为您的PlayerEnemy 类的代码是相同的,所以我建议您创建一个超类 来保存这个逻辑:

class Piece
  attr_accessor :name, :hp, :damage
  def initialize(name, hp, damage)
    @name = name
    @hp = hp
    @damage = damage
  end

  def attack(opponent)
    opponent.hp -= @damage
    puts "#{@name} attacks #{opponent.name}!"
    puts "#{opponent.name}'s HP: #{opponent.hp}"
  end
end

然后为PlayerEnemy 创建子类

class Player < Piece
end

class Enemy < Piece
end

通过这种结构,您可以创建任意数量的敌人和碎片,并让它们分别相互交互:

> hero = Player.new("Zeus", 1000, 100)
=> #<Player:0x007fbd33958498 @name="Zeus", @hp=1000, @damage=100> 
> goul = Enemy.new("Pariah", 400, 50)
=> #<Enemy:0x007fbd33949b78 @name="Pariah", @hp=400, @damage=50>
> ghost = Enemy.new("Bane", 600, 75)
=> #<Enemy:0x007fbd33937680 @name="Bane", @hp=600, @damage=75> 


> hero.attack(goul)
Zeus attacks Pariah!
Pariah's HP: 300
=> nil

【讨论】:

    【解决方案2】:

    由于PlayerEnemy 的所有代码都是相同的,我可以在父类中对它们进行建模(给它一个愚蠢的名称Man,你可以给它一个花哨的名称:D)删除所有代码重复,而不是从公共类继承。

    可以有多种方式在两个对象之间进行交互。我采取了最简单的方法,将另一个对象传递给attack 函数并开始与之交互。

    我将通过以下方式更改此代码:

    class Man
        attr_accessor :name, :hp, :damage
        def initialize(name, hp, damage)
            @name = name
            @hp = hp
            @damage = damage
        end
    
        def attack opposite_team_man
            puts "#{self.name} attacks #{opposite_team_man.name}!"
            opposite_team_man.hp -= @damage
            puts opposite_team_man.hp
        end
    
    end
    class Player < Man
    end
    
    class Enemy < Man
    end  
    
    goodguy = Player.new("Nicehero", 15, 5)
    badguy = Enemy.new("Eviljerk", 15, 5)
    
    goodguy.attack badguy
    

    【讨论】:

    • puts "#{self.name} attacks #{opposite_team_man.name}!" 正在工作,但是当我尝试运行它时,我得到了一个undefined method 'hp' for #&lt;Enemy:0x14a2f8 @hp=15, @name="Eviljerk", @damage=5&gt; (NoMethodError)。知道为什么吗?
    • 啊,因为,这应该是attr_accessor :name, :hp, :damage,更新了答案。
    • 糟糕!我使用的是; 而不是, ......这是有道理的,它的工作方式与我想要的完全一样。感谢您的帮助!
    猜你喜欢
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多