目前項目組正在作的是一款ARPG於MMO結合的遊戲,下面遊戲中AI實現的方式。node
AI配置使用python腳本,實現方式上使用僞行爲樹的結構,實現約定好關鍵字的意思,結構以下:python
# ai配置說明文檔 data = { # 狀態節點 'state_1': { 'action': [警惕距離, 追擊距離], 'patroll': [巡邏距離, 巡邏次數], 'act':[初始動做(坐、站、蹲等)], # 條件節點,知足條件時,會執行後面的act 'conds':{ # 配置方式:'節點名': [判斷類型(>, <, =, %), 數值, 時間, 機率](未使用填-1) 'once': [['=', -1, 'act_1', -1, -1]], # 當即執行act_1 'blood':[['<', '0.5', 'act_2', -1, -1]], # 血量小於0.5時執行act2 'time':[['%' ,'10', 'act_3', -1, 80]], # 每隔10秒有0.8的機率執行一次act_3 ... } }, 'state_2':... ... 'state_n': ... # 行爲節點 'act_1':{ # 配置方式:'節點名':參數 'color': FF0000, # 變爲紅色 'buff': 1000, # 得到buff值1000 'talk': ['我能夠說話啦'], # 說話 'skill': [技能id, 技能id], # 技能 'cd': [技能cd, 技能cd]], # 對應技能cd 'callmonster':[[怪物id, 怪物ai, 數量, 是否隨屬主一塊兒死亡]], # 召喚怪物 }, 'act_2':... ... 'act_n':... }
配置說明裏麪包含了遊戲中支持的ai配置,固然後面能夠在一個個擴充。
根據上面的配置說明,能夠獲得以下的配置:app
# 1000.py data = { 'state_1': { 'action': [100, 150], 'conds': { 'blood': [['<', 0.9, 'act_1', 0], ['<', 0.7, 'act_2', 0], ['<', 0.35, 'act_3', 0]], 'time':[['=', 10, 'act_4' , 80]], }, }, 'act_2':{ 'skill': [10022, 10021], 'cd':[[10022, 0.5]], } 'act_3':{ 'buff':[10003], 'skill': [10023 , 10022, 10021], 'cd':[[10022, 0.6],[10023, 0.7]], } 'act_4':{ 'callmonster':[[1000, 1000, 5, 1]], } }
在每一個怪物的身上會有一個AIMgr來負責管理AI配置:code
class AIMgr(object): """AI管理器""" def __init__(self, monster): self.ai_id = 0 self.ai_data = None self.monster = monster self.cond_objs = [] def set_ai(self, ai_id): self.ai_id = ai_id self.ai_data = ReadAIData(ai_id) self.set_state(self.ai_data.get('state_1')) def set_state(self, state_data): action = state_data.get('action', None) if action is not None: self.monster.set_action(action) patroll = state_data.get('patroll', None) if patroll is not None: self.monster.set_patroll(patroll) act = state_data.get('act') if act is not None: self.monster.default_ani = act ... self.cond_objs = [] conds = state_data.get('conds', None) if conds is not None: for key, cond_list in conds.iteritems(): cond_items = [] for item in cond_list: cond_items.append(AICondition(self, item)) self.cond_objs[k] = cond_items def decision(self, key, val): cond_items = self.cond_objs.get(key, []) for item in cond_items: if item.decision(val): act_node_name = item.act_node_name if item.ai_node is None: data = self.ai_data.get(act_node_name) item.ai_node = AINode(self, data, item.time, act_node_name, key) def remove_node(self, cond_name, node): cond_items = self.cond_objs.get(cond_name, []) for items in cond_items: if cond.act_node is node: cond.ai_node = None
另外再講全部的條件都轉換成對象,方便判斷:對象
class AICond(object): """ai條件對象""" def __init__(self, mgr, data): self.mgr = mgr self.operator = data[0] self.value = data[1] self.act_node_name = data[2] self.time = data[3] self.ai_node = None def decision(self, value): if self.operator == '>': return value > self.value elif self.operator == '<': return value < self.value elif self.operator == '=': return value == self.value elif self.operator == '%': return value % self.value == 0
最後,將全部的行爲節點轉換成對象:遊戲
class ActNode(object): """行爲節點""" def __init__(self, ai_mgr, act_data, time, act_name, cond_name): self.time = time self.cond_name = cond_name self.act_name = act_name self.ai_mgr = ai_mgr self.act_data = act_data if self.time > 0: # 永久 add_timer(self.time, 0, self.on_timer) self.enter_act_node() def on_timer(self, tid) self.ai_mgr.remove_node(self.cond_name, self) def enter_act_node(self): skill = self.act_data.get('skill', None) if skill is not None: self.ai_mgr.monster.set_skill(skill) cd = self.act_data.get('cd') if cd is not None: self.ai_mgr.monster.set_skill_cd(cd) talk = self.act_data.get('talk', None) if talk is not None: self.ai_mgr.monster.show_talk(talk) ... def exit(self): # 清除全部設置進去的狀態 # 因此實現還須要在ai_mgr中保存一份原始值
而後在Monster對象中實現對應方法便可。ci