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

发布于 2024-10-15 01:32:42 字数 2350 浏览 3 评论 0原文

我创建这个游戏是为了学习 OOP,但我在其中的一部分遇到了麻烦。这就是给我带来问题的原因:

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

我将 Armor 作为另一个类。我认为问题可能与以下事实有关:在提到保护时我正在调用 @armor.protection在 Armor 和 Player 中提到了 @armor,但我不确定如何解决这个问题,我已经添加了我认为与我的问题相关的所有代码,就像我说的,我对此很陌生,所以请使用术语。菜鸟可以理解。

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 

I've created this game thing in order to learn OOP and I'm having trouble with part of it. Here's what's causing me problems:

I have two classes. On line 3 of class Player, I have some code which is probably way wrong, but basically, what I'm trying to do is use armor to modify how much damage a player receives. I'm getting an error, though: "undefined method 'protection' for nil:NilClass (NoMethodError)

I have Armor as another class. I think the problem might relate to the fact that I am calling @armor.protection when protection is mentioned in Armor and @armor is mentioned in Player, but I am unsure how to fix this. I have added all the code I believe is relevant to my question below. Like I said, I'm really new at this, so please use terminology a noob could understand.

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

EDIT: added additional code to show all of what I've got going on for clarification. I don't expect anyone to read all of what I've got, though. :S It's probabably scary and snarled up. :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 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云巢 2024-10-22 01:32:42

如果您的 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

If your Armor class has a protection method, it would work fine. However it doesn't, so even if you were to call it from inside the Armor class, you'd get the same error. To define it you can either use attr_reader or attr_accessor or define it by hand.

class Armor
  attr_accessor :protection

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

or

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

  def protection
    @protection
  end
end
書生途 2024-10-22 01:32:42

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

除了其他答案中解释的访问器问题(只需将 attr_reader :protection 添加到类 Armor 中)之外,您还忽略了测试场景中的某些内容:)

错误消息给出了提示: nil:NilClass (NoMethodError) 的未定义方法“保护”。鉴于这是在 hit 方法的第一行引起的,这意味着 @armornil,当然 nil< /code> 不是 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 而不是 Player.initialize 中的 Armor.new('nothing', 0)。这样,如果您需要更改 Armor 内部的工作方式,您可以同时更新虚拟盔甲,而无需触及其他类。

I just ran your 2nd (full) example.

Besides the accessor problem explained in the other answers (just add attr_reader :protection to class Armor), you overlooked something in the test scenario :)

The error message gives a hint: undefined method 'protection' for nil:NilClass (NoMethodError). Given that this is caused in the 1st line of the hit method, this means @armor was nil, and of course nil is not an instance of Armor, so it has no protection method. Why was it nil? Well, look at how your fight begins:

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

Only Melanie has a shirt, and you gave the monster no armor at all! Not very fair, is it :)

To fix that, you either need to give him some armor, or change your hit method so that it still works when @armor was not initialized. A nice OO way of doing that is to initialize all players with a default dummy armor that provides no protection:

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

Done!


Now, since that dummy armor will be useful whatever the specific rules of your game are, I'd abstract it from the point of view of class Player, by making class Armor responsible for creating it instead:

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

Then you can just say Armor.none instead of Armor.new('nothing', 0) in Player.initialize. This way, if you need to change how Armor works internally, you can update the dummy armor at the same time, and without touching other classes.

纵情客 2024-10-22 01:32:42

这里的问题是您有一个 @protection 实例变量,但没有“访问器”来访问它。实例变量对于它们所属的类的实例来说是私有的,因此如果您想将它们公开给外界,则必须设置访问器来执行此操作。在这种情况下,您希望:

class Armor
  attr_reader :protection
  ...
end

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

The problem here is that you have a @protection instance variable, but no "accessor" to get to it. Instance variables are private to the instance of the class they're owned by, so if you want to expose them to the outside world, you have to set up accessors to do so. In this case, you want:

class Armor
  attr_reader :protection
  ...
end

This will let you call @armor.protection, and will return the value of your armor instance's @protection variable.

爱已欠费 2024-10-22 01:32:42

试试这个:

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

player.hit(10)

Try this:

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

player.hit(10)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文