重构游戏中的“命中”值
我正在制作一个游戏,其中有一个方法用来根据角色的技能值计算基础命中数。现在这个方法是一个一个地计算每个值,因为每个技能可以在近、中、远不同的距离使用。
我最开始想把这些技能放在一个元组里,然后循环遍历这个元组,动态地生成每个命中数。但我不太确定这样做是否可行,因为我现在每个命中数都是单独用变量来存储的。
我还考虑过为每个距离创建一个方法,然后把元组作为参数传进去。我可以创建一个新的元组或列表来存储结果值,然后再把这些值分配给各个变量,但我觉得这样做并没有比现在的方式更好,除了看起来不会那么像是复制粘贴。
这是我现在的代码:
def calcBaseHitNumbers(self, dict):
"""Calculate character's base hit numbers depending on skill level."""
self.skill_dict = dict
self.rifle = self.skill_dict.get('CRM', 0)
self.pistol = self.skill_dict.get('PST', 0)
self.big_gun = self.skill_dict.get('LCG', 0)
self.heavy_weapon = self.skill_dict.get('HW', 0)
self.bow = self.skill_dict.get('LB', 0)
#self.skill_tuple = (self.rifle, self.pistol, self.big_gun, self.heavy_weapon,
# self.bow)
#---Short range
## for skill in self.skill_tuple:
## self.base_hit_short = skill * 0.6
self.charAttribs.bhCRM_short = self.rifle * 0.6
self.charAttribs.bhPST_short = self.pistol * 0.6
self.charAttribs.bhHW_short = self.heavy_weapon * 0.6
self.charAttribs.bhLCG_short = self.big_gun * 0.6
self.charAttribs.bhLB_short = self.bow * 0.6
#---Med range
self.charAttribs.bhCRM_med = self.rifle * 0.3
self.charAttribs.bhPST_med = self.pistol * 0.3
self.charAttribs.bhHW_med = self.heavy_weapon * 0.3
self.charAttribs.bhLCG_med = self.big_gun * 0.3
self.charAttribs.bhLB_med = self.bow * 0.3
#---Long range
self.charAttribs.bhCRM_long = self.rifle * 0.1
self.charAttribs.bhPST_long = self.pistol * 0.1
self.charAttribs.bhHW_long = self.heavy_weapon * 0.1
self.charAttribs.bhLCG_long = self.big_gun * 0.1
self.charAttribs.bhLB_long = self.bow * 0.1
你会怎么改进这个代码,让它更灵活一些呢?
编辑:我想做的事情大概是这样的:有一个元组(就像我注释掉的那个),然后循环遍历三次,每次根据特定距离的修正值为每个技能生成一个新值。然后这个结果值会自动分配给对应的变量。
在我脑海里,这个想法是合理的。但当我真的尝试编码的时候,我就迷糊了。我觉得问题在于这是我写的第一个“真正”的程序;之前我写的都是一些小脚本。
这只是我程序的0.1版本,所以现在重构并不是特别重要。不过,我觉得手动这样做不太符合Python的风格,我也想为将来可能的变化做好准备。
5 个回答
我会为角色的属性创建一个单独的类,这样就不会在角色类里放太多东西。同时,也会为武器的属性创建一个类:
class WeaponAttribute(object):
short_mod = 0.6
med_mod = 0.3
long_mod = 0.1
def __init__(self, base):
self.base = base
@property
def short(self):
return self.base * self.short_mod
@property
def med(self):
return self.base * self.med_mod
@property
def long(self):
return self.base * self.long_mod
class CharacterAttributes(object):
def __init__(self, attributes):
for weapon, base in attributes.items():
setattr(self, weapon, WeaponAttribute(base))
在角色类中有一个 CharacterAttributes
对象,可以这样使用:
# Initialise
self.charAttribs = CharacterAttributes(self.skill_dict)
# Get some values
print self.charAttribs.CRM.short
print self.charAttribs.PST.med
print self.charAttribs.LCG.long
让我来看看我是否理解你的情况:每种武器都有自己独特的命中点,比如步枪可能有1个命中点,重型武器可能有2个等等。然后每个角色都有短、中、长三种值,这些值会和武器的命中点相乘。
你可以考虑使用一种叫做策略设计的方法。也就是说,先创建一个武器的父类,里面有一个命中点的属性。然后再为步枪、手枪、弓箭等创建子类。我相信这些武器之间的区别不仅仅是命中点。
接着,角色可以根据你的游戏玩法拥有一种或多种武器。要计算某个特定武器的命中点,其实很简单:
current_weapon * self.medium
如果你决定以后再添加更多武器,那么你就不需要修改角色的代码,因为你的角色可以处理任何武器。
用伪Python表示:
class Weapon
hit = 1
#other properties of weapon
class Rifle(Weapon)
#other properties of Rifle
class Pistol(Weapon)
#other properties of Pistol
class Character
weapon = Rifle()
long=0.6
def calcHit()
return self.long*weapon.hit
john = Character()
john.weapon= Rifle()
john.calcHit
看起来你真正想要的是一个表示武器的类,这个类里有一些属性来处理基本数值,并计算在不同情况下的命中值。这里有个简单的例子:
SHORT_RANGE = 'S'
MEDIUM_RANGE = 'M'
LONG_RANGE = 'L'
SHORT_RANGE_MODIFIER = 0.6
MEDIUM_RANGE_MODIFIER = 0.3
LONG_RANGE_MODIFIER = 0.1
class Weapon(object):
def __init__(self, code_name, full_name, base_hit_value,
short_range_modifier=None, medium_range_modifier=None,
long_range_modifier=None):
self.code_name, self.full_name = code_name, full_name
self.base_hit_value = base_hit_value
self.range_modifiers = {
SHORT_RANGE: short_range_modifier or SHORT_RANGE_MODIFIER,
MEDIUM_RANGE: medium_range_modifier or MEDIUM_RANGE_MODIFIER,
LONG_RANGE: long_range_modifier or LONG_RANGE_MODIFIER,
}
def hit_value(self, range, modifier=1):
return self.base_hit_value * self.range_modifiers[range] * modifier
接下来,你可以在角色对象里创建武器的实例,像这样:
self.rifle = Weapon('CRM', 'rifle', 5)
self.pistol = Weapon('PST', 'pistol', 10)
然后,如果角色在近距离开枪,比如说用手枪:
hit_value = self.pistol.hit_value(SHORT_RANGE)
hit_value() 方法里的额外参数可以用来传入角色或特定情况的修改值。
当然,接下来的步骤可以是把武器直接建模为武器类的子类(也许可以细分成具体的武器类型,比如枪、弓、手榴弹等等,每种都有自己的基本数值),并添加一个库存类来表示角色正在携带的武器。
这些都是比较标准的、无聊的面向对象设计过程,但在很多情况下,这种思路能让你快速入门,并提供一些基本的灵活性。