在另一个类的方法中使用一个类的方法?
我创建这个游戏是为了学习 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您的 Armor 类具有
protection
方法,那么它会正常工作。但事实并非如此,因此即使您从Armor
类内部调用它,您也会收到相同的错误。要定义它,您可以使用attr_reader
或attr_accessor
或手动定义它。或者
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 theArmor
class, you'd get the same error. To define it you can either useattr_reader
orattr_accessor
or define it by hand.or
我刚刚运行了你的第二个(完整)示例。
除了其他答案中解释的访问器问题(只需将
attr_reader :protection
添加到类Armor
中)之外,您还忽略了测试场景中的某些内容:)错误消息给出了提示:
nil:NilClass (NoMethodError) 的未定义方法“保护”
。鉴于这是在hit
方法的第一行引起的,这意味着@armor
是nil
,当然nil< /code> 不是
Armor
的实例,因此它没有protection
方法。为什么为零?好吧,看看你们的战斗是如何开始的:只有梅兰妮有一件衬衫,而你根本没有给怪物任何盔甲!这不太公平,是吗:)
要解决这个问题,您要么需要给他一些盔甲,要么更改您的
hit
方法,以便在@armor
不存在时它仍然有效已初始化。一个很好的面向对象方法是用不提供保护的默认虚拟盔甲初始化所有玩家:完成!
现在,由于无论游戏的具体规则是什么,虚拟盔甲都会很有用,我从类
Player
的角度抽象它,通过让类Armor
负责创建它:然后你可以说
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 classArmor
), 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 thehit
method, this means@armor
wasnil
, and of coursenil
is not an instance ofArmor
, so it has noprotection
method. Why was it nil? Well, look at how your fight begins: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: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 classArmor
responsible for creating it instead:Then you can just say
Armor.none
instead ofArmor.new('nothing', 0)
inPlayer.initialize
. This way, if you need to change howArmor
works internally, you can update the dummy armor at the same time, and without touching other classes.这里的问题是您有一个 @protection 实例变量,但没有“访问器”来访问它。实例变量对于它们所属的类的实例来说是私有的,因此如果您想将它们公开给外界,则必须设置访问器来执行此操作。在这种情况下,您希望:
这将允许您调用
@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:This will let you call
@armor.protection
, and will return the value of your armor instance's@protection
variable.试试这个:
Try this: