我正在尝试在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
对象进行交互。当我尝试让两个班级互相交流时,我似乎无法使其工作;另外,#{variable.name}并不是我试图让函数报告这些值的唯一方法,但我似乎无法找到如何实际引用该对象。
显然,对于对象如何交互或我的代码正在做什么以及我认为它应该做什么,我都缺少一些东西。我将不胜感激任何关于让这两个类进行交互的建议,或者如何重写它以使其按预期运行。
答案 0 :(得分:4)
由于Player
和Enemy
的所有代码都相同,我可以在父类中对它们进行建模(给它一个愚蠢的名字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
答案 1 :(得分:4)
正如@JacobM所提到的,你遇到的问题与你的类无法在不明确地将它们作为参数传递的情况下知道彼此的其他实例有关。虽然您使用全局变量来保存对敌人和玩家的引用的初步解决方法是可行的,但强烈建议不要这样做,因为它会在整个游戏体中“泄漏”程序的逻辑,这通常是不受欢迎的(有关为何要避免它们的详细解释,请参阅Global Variables are Bad。)
从代码中删除$
后,player
在attack
方法中定义后成为局部变量:
def attack
puts "#{self.name} attacks #{goodguy.name}!"
player.hp -= @damage
puts player.hp
end
在此构造中,要作为player
类的实例引用的Player
变量实际上是您在方法体中声明的未定义局部变量。由于您的Player
和Enemy
类的代码相同,我建议您创建一个超类来保存此逻辑:
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
然后为Player
和Enemy
创建子类:
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