Veri Odaklı Tasarım
Geçenlerde kod incelemesine bu soru gibi bir şey gönderdim .
Bazı öneri ve iyileştirmelerden sonra, sonuç bir sözlüğe (veya JSON'a) dayanarak silah yaratmada biraz esneklik sağlayacak basit bir kod oldu. Veriler çalışma zamanında yorumlanır ve basit bir doğrulama, Weapon
tüm komut dosyası yorumlayıcısına güvenmeksizin sınıf tarafından yapılır .
Veri Odaklı Tasarım, Python'un yorumlanmış bir dil olmasına rağmen (hem kaynak hem de veri dosyaları onları yeniden derlemeye gerek kalmadan düzenlenebilir), sunduğunuz gibi durumlarda doğru olanı sesler. Bu soru kavramı, artıları ve eksileri hakkında daha fazla ayrıntıya giriyor. Ayrıca Cornell Üniversitesi hakkında bu konuda güzel bir sunum .
Python aslında veri x motor etkileşimini ve genel olarak komut dosyasını işlemek için bir komut dosyası dili (LUA gibi) ve genel olarak komut dosyası işlemesi için muhtemelen bir komut dosyası dili ve Cd gibi diğer dillerle karşılaştırıldığında, Python gerçekten yapabilir kendi üzerindeki tüm (standart dikkate alınarak dict
değil, aynı zamanda weakref
özellikle kaynak yükleme ve önbelleğe alma için, ikincisi).
Bununla birlikte, bağımsız bir geliştirici, bu makalede önerildiği gibi, veri odaklı yaklaşımı uç noktalarına taşımayabilir :
Veri odaklı tasarım hakkında ne kadarım? Bir oyun motorunun tek bir oyuna özgü kod satırı içermesi gerektiğini düşünmüyorum. Bir değil. Kodlanmış silah türü yok. Kodlanmış HUD düzeni yok. Kodlanmış birim AI yok. Nada. Zip. Sıfır.
Belki, Python ile, hem üretkenlik hem de genişletilebilirlik hedefiyle hem nesne yönelimli hem de veri odaklı yaklaşımın en iyilerinden yararlanılabilir.
Basit örnek işleme
Kod incelemesinde tartışılan özel durumda, bir sözlük hem "statik nitelikler" hem de yorumlanacak mantığı - silahın herhangi bir şartlı davranışa sahip olması halinde saklayacaktır.
Aşağıdaki örnekte bir kılıç, 'antipaladin' sınıfının karakterlerinin elinde bazı yetenek ve istatistiklere sahip olmalı ve diğer karakterler tarafından kullanıldığında daha düşük istatistiklerle sonuçlanmamalı):
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]
}
]
}
}
Sınama amacıyla, basit Player
ve Weapon
sınıflar oluşturdum : silahı tutan / donatacak ilk (böylece koşullu on_equip ayarını çağırarak) ve ikincisi, bir Weapon
başlatma sırasında tartışma . Uygun oyun sınıfları tasarımını yansıtmazlar, ancak verileri test etmek için hala yararlı olabilirler:
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)
Gelecekteki gelişmelerle birlikte, bunun bir gün dinamik bir ustalık sistemine sahip olmamı, tüm silahlar yerine silah bileşenlerini işlememi sağlayacağımı umuyorum ...
Ölçek
- A karakteri bir silah seçer, donatır (istatistiklerini yazdırırız), sonra düşürür;
- B karakteri aynı silahı alır, onu donatır (ve nasıl farklı olduklarını göstermek için istatistiklerini tekrar basarız).
Bunun gibi:
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()
Yazdırmalı:
Bir ozan için
Geliştirme: 2, Hit efektleri: [], Diğer efektler: []
Bir antipaladin için
Geliştirme: 5, Hit etkileri: ['unholy'], Diğer etkiler: ['unholy aurea']