ARPG遊戲中怪物AI實現

目前項目組正在作的是一款ARPG於MMO結合的遊戲,下面遊戲中AI實現的方式。node

一 AI配置

1 配置說明

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':...
}

2 配置實例

配置說明裏麪包含了遊戲中支持的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

相關文章
相關標籤/搜索