Ruby 在另一个类的方法中使用一个类的方法?

Ruby 在另一个类的方法中使用一个类的方法?,ruby,class,methods,Ruby,Class,Methods,我创建这个游戏是为了学习OOP,但我在部分方面遇到了问题。以下是给我带来问题的原因: 我有两节课。在类玩家的第3行,我有一些可能是错误的代码,但基本上,我想做的是使用护甲来修改玩家受到的伤害。不过,我得到了一个错误:nil:NilClass NoMethodError的未定义方法“protection” 我有盔甲作为另一个职业。我认为这个问题可能与我在《盔甲》中提到防护和《玩家》中提到@armor时,我会调用@armor.protection有关,但我不确定如何解决这个问题。我已经添加了我认为与

我创建这个游戏是为了学习OOP,但我在部分方面遇到了问题。以下是给我带来问题的原因:

我有两节课。在类玩家的第3行,我有一些可能是错误的代码,但基本上,我想做的是使用护甲来修改玩家受到的伤害。不过,我得到了一个错误:nil:NilClass NoMethodError的未定义方法“protection”

我有盔甲作为另一个职业。我认为这个问题可能与我在《盔甲》中提到防护和《玩家》中提到@armor时,我会调用@armor.protection有关,但我不确定如何解决这个问题。我已经添加了我认为与我下面的问题相关的所有代码。就像我说的,我在这方面很新,所以请使用noob能理解的术语

class Player
  def equip(armor)
    @armor = armor
  end

  def hit(damage)
    #damage = damage - @armor.protection
    @health -= damage
  end
end  

class Armor
  def initialize(name, protection)
    @protection = protection
  end
end
编辑:添加了额外的代码,以显示所有我正在进行的澄清。不过,我并不指望有人能看完我所有的资料它可能很吓人,而且乱七八糟P

class Player 

  def initialize(name, health) 
    @name = name 
    @health = health 
  end 

  def equip(armor) 
    @armor = armor 
  end 

  def health 
    @health 
  end 

  def health=(value) 
    @health = value 
  end 

  def hit(damage) 
damage = damage - @armor.protection 
    @health -= damage 
  end 

  def dead? 
if @health <= 0 
return true 
elsif @health > 0 
return false 
end 
  end 

  def name 
    @name 
  end 

  def attack(target) 
    damage = rand(30) 
    puts "#{@name} attacks #{target.name}" 
target.hit(damage) 
puts "#{@name} hits #{target.name} for #{damage} damage." 
  end 
end 

class Armor 
  def initialize(name, protection) 
  @protection = protection 
  end 
end 


player1 = Player.new("Melanie", 100) 
player2 = Player.new("a Monster", 200) 
shirt = Armor.new('shirt', 4) 
player1.equip(shirt) 

while player1.dead? == false && player2.dead? == false 
  player1.attack(player2) 
    if player2.health > 0 
      puts "#{player2.name}'s health is at #{player2.health}." 
    elsif player2.health <= 0 
puts "#{player2.name} has no health." 
end 
  player2.attack(player1) 
    if player1.health > 0 
      puts "#{player1.name}'s health is at #{player1.health}." 
    elsif player1.health <= 0 
puts "#{player1.name} has no health." 
end 
end 

if player1.health > player2.health 
  puts "#{player2.name} is dead." 
  puts "#{player1.name} wins." 
elsif player2.health > player1.health 
  puts "#{player1.name} is dead." 
  puts "#{player2.name} wins." 
elsif player2.health == player1.health 
  puts "#{player1.name} and #{player2.name} killed each other." 
end 
试试这个:

player = Player.new 
armor = Armor.new('Mythril', 100)
player = player.equip(armor)  #Initialise the armor object inside Player.

player.hit(10)
试试这个:

player = Player.new 
armor = Armor.new('Mythril', 100)
player = player.equip(armor)  #Initialise the armor object inside Player.

player.hit(10)
如果你的护甲等级有一个防护方法,它会很好的工作。但是它不是,所以即使你从装甲类内部调用它,你也会得到同样的错误。要定义它,可以使用attr\u reader或attr\u accessor,也可以手动定义

class Armor
  attr_accessor :protection

  def initialize(name, protection)
    @protection = protection
  end
end

如果你的护甲等级有一个防护方法,它会很好的工作。但是它不是,所以即使你从装甲类内部调用它,你也会得到同样的错误。要定义它,可以使用attr\u reader或attr\u accessor,也可以手动定义

class Armor
  attr_accessor :protection

  def initialize(name, protection)
    @protection = protection
  end
end


这里的问题是您有一个@protection实例变量,但没有访问器。实例变量对于它们所属的类的实例是私有的,因此,如果要将它们公开给外部世界,必须设置访问器。在这种情况下,您需要:

class Armor
  attr_reader :protection
  ...
end

这将允许您调用@armor.protection,并返回armor实例的@protection变量的值。

这里的问题是您有一个@protection实例变量,但没有访问器。实例变量对于它们所属的类的实例是私有的,因此,如果要将它们公开给外部世界,必须设置访问器。在这种情况下,您需要:

class Armor
  attr_reader :protection
  ...
end

这将允许您调用@armor.protection,并将返回您的装甲实例的@protection变量的值。

我刚刚运行了您的第二个完整示例

除了在其他答案中解释的访问者问题之外,只需添加attr_reader:protection to class Armor,您在测试场景中忽略了一些东西:

错误消息给出提示:nil:NilClass NoMethodError的未定义方法“protection”。考虑到这是在命中方法的第1行中造成的,这意味着@armor是零,当然,零不是装甲的一个实例,因此它没有保护方法。为什么是零?好吧,看看你的战斗是如何开始的:

player1 = Player.new("Melanie", 100) 
player2 = Player.new("a Monster", 200) 
shirt = Armor.new('shirt', 4)
player1.equip(shirt) 
只有梅勒妮有一件衬衫,而你却没有给怪物任何盔甲!不太公平,是不是:

要解决这个问题,你要么给他一些护甲,要么改变你的命中方法,使它在@armor未初始化时仍然有效。一个很好的OO方法是使用默认的虚拟盔甲初始化所有玩家,该盔甲不提供任何保护:

class Player
  def initialize(name, health)
    @armor = Armor.new('nothing', 0)
    # ...
完成了

现在,由于无论游戏的具体规则是什么,虚拟盔甲都是有用的,我将从职业玩家的角度抽象它,让职业盔甲负责创建它:

class Armor
  class << self # define a class method, like new
    def none
      self.new('nothing', 0)
    end
  end
  # ...

然后你可以说Armor.none而不是Armor.new'nothing',Player.initialize中的0。这样,如果您需要更改装甲内部的工作方式,您可以同时更新虚拟装甲,而不必涉及其他类。

我刚刚运行了您的第二个完整示例

除了在其他答案中解释的访问者问题之外,只需添加attr_reader:protection to class Armor,您在测试场景中忽略了一些东西:

错误消息给出提示:nil:NilClass NoMethodError的未定义方法“protection”。考虑到这是在命中方法的第1行中造成的,这意味着@armor是零,当然,零不是装甲的一个实例,因此它没有保护方法。为什么是零?好吧,看看你的战斗是如何开始的:

player1 = Player.new("Melanie", 100) 
player2 = Player.new("a Monster", 200) 
shirt = Armor.new('shirt', 4)
player1.equip(shirt) 
只有梅勒妮有一件衬衫,而你却没有给怪物任何盔甲!不太公平,是不是:

要解决这个问题,你要么给他一些护甲,要么改变你的命中方法,使它在@armor未初始化时仍然有效。一个很好的OO方法是使用默认的虚拟盔甲初始化所有玩家,该盔甲不提供任何保护:

class Player
  def initialize(name, health)
    @armor = Armor.new('nothing', 0)
    # ...
完成了

现在,由于无论游戏的具体规则是什么,虚拟盔甲都是有用的,我将从职业玩家的角度抽象它,让职业盔甲负责创建它:

class Armor
  class << self # define a class method, like new
    def none
      self.new('nothing', 0)
    end
  end
  # ...
然后你可以说armar.none代替armar.new'nothing',在Player.in中为0

初始化。这样,如果您需要更改盔甲的内部工作方式,您可以同时更新虚拟盔甲,而不必接触其他类。

应该是player=player.new和player.equiparmbor和player.hit10,这些都是实例方法。我想我已经有类似的方法了。我已经添加了所有需要澄清的代码。希望它有意义。应该是player=player.new和player.equiparmbor和player.hit10,这些都是实例方法。我想我已经有了类似的东西。我已经添加了所有需要澄清的代码。希望这是有意义的。这确实帮助我理解了attr_阅读器,attr_访问器,因为我以前从未得到过它,但我认为我的部分问题是我没有将装甲与装甲绑定在一起。我不知道该怎么做。到目前为止,程序还不知道说盔甲,我的意思是,在这个球员的情况下,一件球衣。除了在damage=damage-@armor.protection中,我唯一提到的护甲是小写字母a,它与职业玩家装备的定义一致:这无疑帮助我理解了attr_阅读器,attr_访问器,因为我以前从未得到过它,但我认为我的部分问题是我没有将装甲与装甲绑定在一起。我不知道该怎么做。到目前为止,程序还不知道说盔甲,我的意思是,在这个球员的情况下,一件球衣。除了在damage=damage-@armor.protection中,我唯一提到的护甲是小写字母a,它与职业玩家装备的定义一致:现在的SAs,程序不知道说盔甲,我的意思是,在这个球员的情况下,一件衬衫。除了在damage=damage-@armar.protection中,我唯一提到的护甲是小写字母a,它的定义是在类玩家中装备。我尝试了第二个例子,希望它能解决这个问题,但无论哪种情况,我仍然有相同的错误。我知道我有点不知所措,但我确实了解很多,这绝对是一次学习经历S@Melanie:首先,我的代码是错误的,因为当我提到保护时,我无意中键入了armor,所以它无法工作。现在我修复了它,只要你在调用任何使用@armor的方法之前调用Equipm,它就会工作。要求首先调用Equipm的一个更好的解决方案可能是在玩家类初始化方法中将@armor初始化为零的armor类实例。这样一来,如果玩家一开始没有盔甲,你就不必担心了。仅供参考和谷歌素材:@Mike Bethany的建议是空对象重构。到目前为止,程序不知道说盔甲,我的意思是,在这个玩家的情况下,一件衬衫。除了在damage=damage-@armar.protection中,我唯一提到的护甲是小写字母a,它的定义是在类玩家中装备。我尝试了第二个例子,希望它能解决这个问题,但无论哪种情况,我仍然有相同的错误。我知道我有点不知所措,但我确实了解很多,这绝对是一次学习经历S@Melanie:首先,我的代码是错误的,因为当我提到保护时,我无意中键入了armor,所以它无法工作。现在我修复了它,只要你在调用任何使用@armor的方法之前调用Equipm,它就会工作。要求首先调用Equipm的一个更好的解决方案可能是在玩家类初始化方法中将@armor初始化为零的armor类实例。这样一来,如果玩家一开始没有盔甲,你就不用担心了。仅供参考和谷歌素材:@Mike Bethany的建议是空对象重构。哇!太棒了!非常感谢你!我不会认为这是百万年来的问题。我必须学会更好地阅读错误消息。至少我比老天爷高了几步!一个错误!不客气。顺便说一句,如果我能挑出更多的细节,我会在玩家1死的时候看到它false&&player2.dead?==错误的笨拙的风格!至少,用非某个布尔值替换某个布尔值==false;就我个人而言,我会代替死者?由一个活的谓词进行谓词?一个你可以直接使用而不用否定的词:是的,我朋友就是这么说的!非常感谢。哇!太棒了!非常感谢你!我不会认为这是百万年来的问题。我必须学会更好地阅读错误消息。至少我比老天爷高了几步!一个错误!不客气。顺便说一句,如果我能挑出更多的细节,我会在玩家1死的时候看到它false&&player2.dead?==错误的笨拙的风格!至少,用非某个布尔值替换某个布尔值==false;就我个人而言,我会代替死者?由一个活的谓词进行谓词?一个你可以直接使用而不用否定的词:是的,我朋友就是这么说的!非常感谢。