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

时间:2011-01-29 12:08:22

标签: ruby class methods

我是编程新手,但我很想学习,所以请原谅这个问题。我创造了这个游戏的东西,以帮助我学习OOP,我遇到了部分问题。这就是导致我出现问题的原因:

我有两节课。在Player类的第3行,我有一些可能错误的代码,但基本上,我正在尝试做的是使用armor来修改玩家受到的伤害。我收到一个错误:“nil的未定义方法'保护':NilClass(NoMethodError)

我将Armor作为另一个班级。我认为这个问题可能与我在Armor中提到保护并且在Player中提到@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

编辑:添加了额外的代码,以显示我正在进行澄清的所有内容。 但我不希望任何人阅读我所拥有的所有内容。 :S这可能是可怕的并且咆哮起来。 :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 

4 个答案:

答案 0 :(得分:3)

如果你的Armor类有一个protection方法,它会正常工作。但它没有,所以即使你从Armor类中调用它,你也会得到同样的错误。要定义它,您可以使用attr_readerattr_accessor或手动定义。

class Armor
  attr_accessor :protection

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

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

  def protection
    @protection
  end
end

答案 1 :(得分:2)

我刚刚运行了你的第二个(完整)示例。

除了存取问题在其他的答案解释(刚加入attr_reader :protectionArmor),你忽略了在测试场景中的东西:)

错误消息提示:undefined method 'protection' for nil:NilClass (NoMethodError)。考虑到这是在hit方法的第一线引起的,此装置@armornil,当然nil不是的一个实例Armor ,所以它没有protection方法。为什么没有?好吧,看看你的战斗是如何开始的:

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

只有梅兰妮有一件衬衫,你根本没给了怪物任何盔甲!不太公平,是吧:)。

要解决这个问题,您可能需要给他一些盔甲,或者改变您的hit方法,使其没有初始化@armor时仍然有效。这样做的一个好方法是使用默认的虚拟装甲初始化所有玩家,不提供任何保护:

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

完成!


现在,既然无论游戏的具体规则如何,那个虚拟装甲都会有用,我会从类Player的角度抽象它,让类Armor负责创建相反:

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

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

答案 2 :(得分:1)

试试这个:

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

player.hit(10)

答案 3 :(得分:1)

这里的问题是你有一个@protection实例变量,但没有“访问者”可以访问它。实例变量对于它们所拥有的类的实例是私有的,因此如果要将它们暴露给外部世界,则必须设置访问器来执行此操作。在这种情况下,您需要:

class Armor
  attr_reader :protection
  ...
end

这样您就可以致电@armor.protection,并返回您的护甲实例@protection变量的值。