डेटा-चालित डिजाइन
मैंने इस प्रश्न को हाल ही में कोड समीक्षा के लिए प्रस्तुत किया ।
कुछ सुझावों और सुधारों के बाद, परिणाम एक सरल कोड था जो एक शब्दकोश (या JSON) के आधार पर हथियार निर्माण पर कुछ सापेक्ष लचीलेपन की अनुमति देगा। डेटा को रनटाइम पर व्याख्यायित किया जाता है Weapon
और पूरी तरह से स्क्रिप्ट दुभाषिया पर भरोसा करने की आवश्यकता के बिना, कक्षा द्वारा ही सरल सत्यापन किए जाते हैं ।
डेटा-चालित डिज़ाइन, पायथन की व्याख्या की गई भाषा होने के बावजूद (स्रोत और डेटा फ़ाइलों को उन्हें फिर से खोलने की आवश्यकता के बिना संपादित किया जा सकता है), आपके द्वारा प्रस्तुत किए गए मामलों जैसे मामलों में करने के लिए सही चीज़ लगती है। यह सवाल अवधारणा, इसके पेशेवरों और विपक्षों के बारे में अधिक विवरण में जाता है। थेरेस ने इसके बारे में कॉर्नेल विश्वविद्यालय में एक अच्छी प्रस्तुति भी दी ।
अन्य भाषाओं की तुलना में, जैसे कि C ++, जो संभवतः डेटा x इंजन इंटरैक्शन और सामान्य रूप से स्क्रिप्टिंग को संभालने के लिए स्क्रिप्टिंग भाषा (जैसे LUA) का उपयोग करेगी, और डेटा को संग्रहीत करने के लिए एक निश्चित डेटा प्रारूप (XML की तरह), पायथन वास्तव में हो सकता है यह सब अपने आप में (मानक को देखते हुए dict
भी weakref
, विशेष रूप से संसाधन लोडिंग और कैशिंग के लिए उत्तरार्द्ध)।
एक स्वतंत्र डेवलपर, हालांकि, इस लेख में सुझाए गए डेटा-संचालित दृष्टिकोण को अपने चरम पर नहीं ले जा सकता है :
डेटा-संचालित डिज़ाइन के बारे में मैं कितना हूँ? मुझे नहीं लगता कि गेम इंजन में गेम-विशिष्ट कोड की एक भी पंक्ति होनी चाहिए। एक नहीं। कोई हार्डकोड हथियार प्रकार नहीं। कोई हार्डकोड HUD लेआउट नहीं। कोई हार्डकोड इकाई एआई। नाडा। ज़िप बंद करें। कुछ भी नहीं।
हो सकता है, पायथन के साथ, कोई भी वस्तु-उन्मुख और डेटा-संचालित दृष्टिकोण दोनों के सर्वोत्तम से लाभ उठा सकता है, जिसका उद्देश्य उत्पादकता और विलुप्तता दोनों हो सकता है।
सरल नमूना प्रसंस्करण
कोड समीक्षा पर चर्चा किए गए विशिष्ट मामले में, एक शब्दकोश "स्थिर विशेषताओं" और व्याख्या किए जाने वाले तर्क दोनों को संग्रहीत करेगा - हथियार में कोई सशर्त व्यवहार होना चाहिए।
एक तलवार के नीचे के उदाहरण में कक्षा 'एंटीपलाडिन' के पात्रों के हाथों में कुछ क्षमताएं और आँकड़े होने चाहिए, और अन्य पात्रों द्वारा उपयोग किए जाने पर कम आँकड़ों के साथ कोई प्रभाव नहीं):
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)
कुछ भविष्य के सुधार के साथ मुझे आशा है कि यह किसी दिन मुझे एक गतिशील क्राफ्टिंग प्रणाली की अनुमति देगा, पूरे भारत के बजाय हथियार घटकों को संसाधित करेगा।
परीक्षा
- चरित्र ए हथियार उठाता है, इसे लैस करें (हम इसके आंकड़े प्रिंट करते हैं), फिर इसे छोड़ दें;
- चरित्र बी एक ही हथियार उठाता है, इसे लैस करें (और हम इसके आंकड़े फिर से प्रिंट करते हैं कि वे कैसे भिन्न हैं)।
ऐशे ही:
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, हिट प्रभाव: ['अपवित्र'], अन्य प्रभाव: ['अपवित्र aurea']