ARPG遊戲中怪物AI實現
阿新 • • 發佈:2019-02-19
目前專案組正在做的是一款ARPG於MMO結合的遊戲,下面遊戲中AI實現的方式。
一 AI配置
1 配置說明
AI配置使用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':...
}
2 配置例項
配置說明裡麵包含了遊戲中支援的ai配置,當然後面可以在一個個擴充。
根據上面的配置說明,可以得到如下的配置:
# 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配置:
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物件中實現對應方法即可。