数据驱动设计
我向 最近将代码审查。
经过一些建议和改进后,结果得到了一个简单的代码,该代码将使在基于字典(或JSON)的武器创建方面具有一定的相对灵活性。数据在运行时进行解释,并且简单的验证由Weapon
类本身完成,而无需依赖整个脚本解释器。
尽管Python是一种解释型语言(无需重新编译即可编辑源文件和数据文件),但数据驱动设计听起来像在您所介绍的情况下正确的做法。这个问题将详细介绍该概念及其优缺点。还有一个不错的在康奈尔大学上介绍。
与其他语言(例如C ++)相比,它可能会使用脚本语言(例如LUA)来处理数据x引擎交互和脚本编写,以及某种数据格式(例如XML)来存储数据,Python实际上可以做到它全部依靠自己(既考虑标准dict
又考虑标准weakref
,后者专门用于资源加载和缓存)。
但是,独立开发人员可能不会像本文中建议的那样将数据驱动方法发挥到极致:
我需要多少数据驱动设计?我认为游戏引擎不应包含一行特定于游戏的代码。不是一个。没有硬编码的武器类型。没有硬编码的HUD布局。没有硬编码的单位AI。娜达 压缩。齐尔奇
也许,使用Python,可以同时从面向对象和数据驱动的方法中受益,以提高生产力和可扩展性。
简单的样品处理
在讨论代码审查的特定情况下,词典将存储“静态属性”和要解释的逻辑-如果武器具有任何条件行为。
在下面的示例中,剑应具有“ antipaladin”类的角色手中的某些能力和属性,并且没有任何效果,其他角色使用时其属性较低):
WEAPONS = {
"bastard's sting": {
# magic enhancement, weight, value, dmg, and other attributes would go here.
"magic": 2,
# Those lists would contain the name of effects the weapon provides by default.
# They are empty because, in this example, the effects are only available in a
# specific condition.
"on_turn_actions": [],
"on_hit_actions": [],
"on_equip": [
{
"type": "check",
"condition": {
'object': 'owner',
'attribute': 'char_class',
'value': "antipaladin"
},
True: [
{
"type": "action",
"action": "add_to",
"args": {
"category": "on_hit",
"actions": ["unholy"]
}
},
{
"type": "action",
"action": "add_to",
"args": {
"category": "on_turn",
"actions": ["unholy aurea"]
}
},
{
"type": "action",
"action": "set_attribute",
"args": {
"field": "magic",
"value": 5
}
}
],
False: [
{
"type": "action",
"action": "set_attribute",
"args": {
"field": "magic",
"value": 2
}
}
]
}
],
"on_unequip": [
{
"type": "action",
"action": "remove_from",
"args": {
"category": "on_hit",
"actions": ["unholy"]
},
},
{
"type": "action",
"action": "remove_from",
"args": {
"category": "on_turn",
"actions": ["unholy aurea"]
},
},
{
"type": "action",
"action": "set_attribute",
"args": ["magic", 2]
}
]
}
}
为了进行测试,我创建了简单类Player
和Weapon
类:第一个类持有/装备武器(因此调用其有条件的on_equip设置),第二类作为单个类,它将根据作为Weapon
初始化期间的参数。它们不能反映正确的游戏类设计,但仍可用于测试数据:
class Player:
"""Represent the player character."""
inventory = []
def __init__(self, char_class):
"""For this example, we just store the class on the instance."""
self.char_class = char_class
def pick_up(self, item):
"""Pick an object, put in inventory, set its owner."""
self.inventory.append(item)
item.owner = self
class Weapon:
"""A type of item that can be equipped/used to attack."""
equipped = False
action_lists = {
"on_hit": "on_hit_actions",
"on_turn": "on_turn_actions",
}
def __init__(self, template):
"""Set the parameters based on a template."""
self.__dict__.update(WEAPONS[template])
def toggle_equip(self):
"""Set item status and call its equip/unequip functions."""
if self.equipped:
self.equipped = False
actions = self.on_unequip
else:
self.equipped = True
actions = self.on_equip
for action in actions:
if action['type'] == "check":
self.check(action)
elif action['type'] == "action":
self.action(action)
def check(self, dic):
"""Check a condition and call an action according to it."""
obj = getattr(self, dic['condition']['object'])
compared_att = getattr(obj, dic['condition']['attribute'])
value = dic['condition']['value']
result = compared_att == value
self.action(*dic[result])
def action(self, *dicts):
"""Perform action with args, both specified on dicts."""
for dic in dicts:
act = getattr(self, dic['action'])
args = dic['args']
if isinstance(args, list):
act(*args)
elif isinstance(args, dict):
act(**args)
def set_attribute(self, field, value):
"""Set the specified field with the given value."""
setattr(self, field, value)
def add_to(self, category, actions):
"""Add one or more actions to the category's list."""
action_list = getattr(self, self.action_lists[category])
for action in actions:
if action not in action_list:
action_list.append(action)
def remove_from(self, category, actions):
"""Remove one or more actions from the category's list."""
action_list = getattr(self, self.action_lists[category])
for action in actions:
if action in action_list:
action_list.remove(action)
我希望通过将来的改进,有一天能使我拥有一个动态的制作系统,可以处理武器组件而不是整个武器。
测试
- 角色A拿起武器,装备它(我们打印其状态),然后放下;
- 角色B选择相同的武器装备(我们再次打印其统计数据以显示它们的不同之处)。
像这样:
def test():
"""A simple test.
Item features should be printed differently for each player.
"""
weapon = Weapon("bastard's sting")
player1 = Player("bard")
player1.pick_up(weapon)
weapon.toggle_equip()
print("Enhancement: {}, Hit effects: {}, Other effects: {}".format(
weapon.magic, weapon.on_hit_actions, weapon.on_turn_actions))
weapon.toggle_equip()
player2 = Player("antipaladin")
player2.pick_up(weapon)
weapon.toggle_equip()
print("Enhancement: {}, Hit effects: {}, Other effects: {}".format(
weapon.magic, weapon.on_hit_actions, weapon.on_turn_actions))
if __name__ == '__main__':
test()
它应该打印:
对于吟游诗人
增强效果:2,命中效果:[],其他效果:[]
对于抗帕拉丁
增强效果:5,命中效果:['unholy'],其他效果:['unholy aurea']