我正在构建一个在调用方法时遇到问题的游戏。一个怪物可以出现,并将得到一个随机武器,如果该武器射程远,怪物会得到一个回合挫折给玩家一个战斗机会。当调用方法monsterRangedTurnSetback时,我得到它试图在nil中找到属性的错误:NilClass。我最终追溯到genWeapon函数,并且该函数无法被调用。她的一些代码
def monsterRangedTurnSetback(weapon)
attribs = weapon.attributes()
attribs.each do |attrib|
if attrib == "Ranged"
return 1
else
return 0
end
end
end
def genWeapon
weaponGen = rand(1..80)
if weaponGen == 1 or weaponGen == 2
weapon = GreatSword.new
hasTwoHandedWeapon = true
elsif weaponGen == (3..23)
weapon = ShortSword.new
hasTwoHandedWeapon = false
elsif weaponGen == (24..34)
weapon = ShortBow.new
hasTwoHandedWeapon = true
elsif weaponGen == (35..48)
weapon = LongBow.new
hasTwoHandedWeapon = true
elsif weaponGen == (49..64)
weapon = Dagger.new
hasTwoHandedWeapon = false
elsif weaponGen == (65..78)
weapon = HandCrossbow.new
hasTwoHandedWeapon = false
elsif weaponGen == 79 or weaponGen == 80
weapon = HeavyCrossbow.new
hasTwoHandedWeapon = true
end
return weapon
puts weapon.name
sleep 2
end
class Orc
attr_accessor :totalDamage, :totalHealth, :armorClass, :attackText, :name,
:turnSetback
def initialize
@wep = genWeapon()
@baseDamage = 7
@weapon = @wep
@turnSetback = monsterRangedTurnSetback(@weapon)
@wep = nil
@health = 5
@hasShield = shield(@weapon)
@armorClass = 6
if @hasShield == true
@armorClass += 2
end
@challengeLevel = 1
@attackText = ["Orc stabs you", "Orc slashes at you", "Orc intimidates you"]
@name = "Orc"
end
end
class ShortSword
attr_reader :attributes, :name, :attackBonus
def initialize
@attributes = ["Melee", "1Hand"]
attackBonus = 3
name = "Short Sword"
end
end
是的,代码按顺序排列,是的,我知道怪物类允许读取不存在的变量。任何帮助表示赞赏。
答案 0 :(得分:1)
这里的错误可能是attr_reader
无法绑定到像x
这样的本地变量,而只能绑定到像@x
这样的实例变量。在您的代码中:
attr_reader :attackBonus
def initialize
# This is a local variable that will fall out of scope once the method
# finishes. It is not saved anywhere, simply thrown away.
attackBonus = 3
end
为其添加@
前缀将使其保持不变并且可读。
同样的事情发生在genWeapon
中,其中设置并丢弃局部变量。如果你需要那些持久化,你需要在回报中包含它们。无论如何,这些属性应该是某种基础武器类的一部分,您可以在其中调用Dagger.new.two_handed?
或Dagger.new.hands_required
。
正如@engineersmnky所指出的那样genWeapon
方法存在严重缺陷,x == (1..2)
永远不会为任何x
的{{1}}值返回true。 的工作原因是(1..2)
或(1..2).include?(x)
。由于(1..2) === x
在内部使用case
,因此可以轻松编写:
===
那仍然很乏味。而是写一个查找表:
case (rand(1..80))
when 1..2
GreatSword.new
when 3..23
ShortSword.new
# ...
end
这个地图滚动到类。然后你的发电机功能变得微不足道了:
WEAPON_PROBABILITY = {
(1..2) => GreatSword,
(3..23) => ShortSword,
(24..34) => ShortBow,
(35..48) => LongBow,
(49..64) => Dagger,
(65..78) => HandCrossbow,
(79..80) => HeavyCrossbow
}.flat_map do |range, type|
range.to_a.map do |roll|
[ roll, type ]
end
end.to_h
利用Ruby的“一切都是对象”原则来制作类的查找表,大大简化了事情,并使代码更容易理解。始终尝试引导您的程序根据数据而不是程序来定义事物。
答案 1 :(得分:1)
您可能想要重新审视如何定义其中一些类。甚至可能在{Weapon}类中包含turn_delay
作为方法。以下是我如何重构这一点来从武器父类中继承专用武器:
class Weapon
attr_reader :attributes, :name, :attack_bonus
def initialize
@attributes = []
end
def turn_delay?
@attributes.include? :ranged
end
def two_handed?
@attributes.include? :two_hand
end
end
class ShortSword < Weapon
def initialize
@attributes = %i(melee one_hand)
@attack_bonus = 3
@name = 'Short Sword'
end
end
class LongBow < Weapon
def initialize
@attributes = %i(ranged)
@attack_bonus = 10
@name = 'Long Bow'
end
end
bow = LongBow.new
puts bow.name
puts bow.turn_delay?
sword = ShortSword.new
puts sword.name
puts sword.turn_delay?
输出:
Long Bow
true
Short Sword
false
我对此有太多的乐趣,大量的武器可能会变得很麻烦,为其编写类定义。既然你选择了Ruby,就可以使用以下内容来接受一些元编程并快速制作新武器(要求你已经定义了基类Weapon
类:
[
{ klass: 'BroadSword', attributes: [:melee, :two_hand], attack_bonus: 20, name: 'Broad Sword' },
{ klass: 'Dagger', attributes: [:melee, :one_hand], attack_bonus: 1, name: 'Dagger' },
{ klass: 'ShortBow', attributes: [:ranged], attack_bonus: 5, name: 'Short Bow' },
].each do |obj|
eval <<WEAPON
class #{obj[:klass]} < Weapon
def initialize
@attributes = #{obj[:attributes]}
@name = '#{obj[:name]}'
@attack_bonus = #{obj[:attack_bonus]}
end
end
WEAPON
end
然后:
bs = BroadSword.new
puts bs.name
puts bs.two_handed?
Broad Sword
true