TrinityCore框架_AI模块
最近更新:2024-09-23
|
字数总计:3.8k
|
阅读估时:15分钟
|
阅读量: 次
AI模块 AI模块概述 行为树举例 基类CreatureAI的封装 野怪AI设计 战场AI设计 SmartAI(SAI) SmartAI概述 SAI代码封装 重构SAI MySQL视图 举例1:格拉克-洛克鲁布(事件链) 举例2:血槌苦力(附加事件条件) 举例3:诺格(NPC与NPC的AI交互) 举例4:血帆术士(状态机) 举例5:克朗-石蹄(延迟动作列表)
AI模块 AI模块概述
智能,游戏中的AI主要指游戏对象具备智能属性
怪物行为
怪物策略
NPC对话
寻路
。。。
游戏AI本质:感知事件,做出反馈
一致反馈
有规律可循
恰当的智力
合理的犯错,暴露给玩家
抓住玩家较大的失误
主流实现方式
状态机
AI行为在有限的几个状态间切换
某一时刻只有一个状态
满足特定条件才能切换到另一种状态
行为树/决策树,不是以状态来描述行为,而以决策来选择行为
基本概念
一个信息从根节点出发,在树中传递,直到到达叶子节点
每个节点都有回调函数,都有返回值:成功或失败或进行中
逻辑节点(有一个或多个子节点)它有责任传递信息到子节点,逻辑节点特性:是否、何时、多少次、或且等不同规则
叶子节点(没有子节点)是实际指令,动作节点是最常见的叶子节点
节点
装饰节点(允许有一个节点)
转换子节点返回的结果
停止子节点执行
重复执行子节点
控制节点(允许多个子节点)
序列 sequence
选择 selector
或操作
只要一个子节点返回true,就返回true
叶子节点(没有子节点)
怪物AI层次设计
稳定(AI/CoreAI)
AggressorAI
CombatAI
NullCreatureAI
ReactorAI
。。。
变化(热更新)
ScriptedAI(修改动态库)
SmartAI(修改数据库)
行为树举例
方形:控制节点
菱形:叶子节点-条件节点
圆形:动作节点
基类CreatureAI的封装
主动:可以采取的策略
被动:事件节点回调
战斗
进入战斗
脱离战斗
选择目标
选择技能
依赖:仇恨列表和战斗列表(进入战斗、脱离等)的实现
视野
进入视野
移动
开始移动
到达目的地
中断移动
对话
野怪AI设计
野怪是如何选择AI的?
配置(dbc)
creature
ScriptName(会覆盖掉template中的ScriptName)
creature_template
AIName(SAI的名字或稳定AI的名字)
ScriptName(配置变化的AI)
smart_script
配置逻辑关系
先看是不是使用变化的AI,也就是先看ScriptName
如果没有配置ScriptName,再去看AIName
如果没有配置ScriptName和AIName,在稳定AI中根据权重进行选择
SelectAI接口实现AI选择
举例:怎么将被动攻击的AI转化为主动攻击
在UpdateAI接口中
判断没有仇恨列表,搜寻附近玩家,调用AttackStart主动攻击
1 2 3 # 聊天窗gm .gm off # 先关掉gm,否则野怪不会攻击玩家 .lookup creature 幼狼 # 查看幼狼的creature_id == 299
1 2 3 select entry, ScriptName, AIName from creature_template where entry = 299 ;
1 2 # 聊天窗gm .npc add temp 299 # 我们在当前位置临时刷新一个幼狼,然后断点查看,幼狼选择的AI(因为野怪是在LoadCreature阶段就选择的AI,所以需要再生成一个才能捕获到)
1 2 3 4 5 typename AIRegistry::RegistryMapType const & items = AIRegistry::instance ()->GetRegisteredItems (); auto itr = std::max_element (items.begin (), items.end (), PermissibleOrderPred <T>(obj));if (itr != items.end () && GetPermitFor (obj, *itr) >= 0 ) return itr->second.get ();
修改AggressorAI,使其在范围内会主动攻击玩家1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void AggressorAI::UpdateAI (uint32 diff) { if (uiTimer <= diff){ if (me->GetThreatManager ().isTreatListEmpty ()){ auto const & plist = me->GetMap ()->GetPlayers (); for (auto iter = plist.begin ();iter!=plist.end ();++iter){ Player* player = iter->GetSource (); if (player && !player->isGameMaster () && me->IsInRange (player, 0.0f , 10.0f ,true )) { AttackStart (player); break ; } } } uiTimer = 5000 ; }else { uiTimer -= diff; } if (!UpdateVictim ()) return ; DoMeleeAttackIfReady (); }
修改稳定AI需要整体编译worldserver,并重启
战场AI设计
战场总结
组队的玩法,.debug bg进入调试模式无需组队进入战场
战场boss血量高攻击高,学习圣盾术(.learn 40733)
战场地图大,可以通过.go xyz boss坐标,快速进入战场副本
GM才可以作上面的操作,GM模式下AI不会开启,进入副本需要关闭GM模式,.gm off
快速结束战场.die boss (通过鼠标选择对象)
ScriptAI
抽象了具体主动动作
通过定时事件来驱动技能释放和对话
1 2 3 4 5 6 7 8 9 10 select entry, ScriptName, AIName, `name`, `subname` from creature_template where entry = 11946 ;select entry, ScriptName, AIName, `name`, `subname` from creature_template where entry = 14773 ;select entry, ScriptName, AIName, `name`, `subname` from creature_template where entry = 14772 ;
SmartAI(SAI) SmartAI概述
表关系
creature
可以配置多个同类型的怪物(具体对象
拥有怪物的坐标
creature_template
类型怪物(某个类型
当AIName == “Smart AI”时使用smartai
smart_scripts
可以配置某个怪物也可以配置类型怪物(使用id正负号区分
某个怪物可以拥有多个AI过程
一个AI过程由事件、动作、对象 构成
参考文档
研究工具
WoWDatabaseEditor
File/settings配置服务器信息
dbc
client
worldserver/authserver
mysql
搜索SAI的怪物视图(Mysql)1 2 3 4 5 select B.entry, A.position_x, A.position_y, A.position_z, C.id, C.link, C.event_type, C.action_type, C.target_type from creature as A join creature_template as B on A.id = B.entry join smart_script as C on B.entry = C.entryorguid where B.AIName = "SmartAI" order by A.guid, C.source_type, C.id, C.link;
SAI代码封装
SmartScriptMgr
主要职责:从SmartScripts表中加载怪物AI过程
辅助函数、宏定义
SmartAI
提供了SmartAI特有的事件感知,动作反馈
复写CreatureAI的行为
SmartScript
主要职责,处理来自数据库配置该怪物的AI的过程
比较:原来AI实现都是通过复写CreatureAI的行为,在该接口中直接实现采用具体反馈动作
现在全部由SmartScript处理
重构SAI MySQL视图
重构的原因
三张表的桥梁应该是creature_template
不需要xyz坐标,需要的是guid1 2 3 4 5 6 7 8 9 select a.guid, b.entry, c.id, c.link, c.event_type, c.action_type, c.target_type from creature as a join creature_template as b on a.id = b.entry join smart_scripts as c on b.entry = c.entryorguid where b.AIName = "SmartAI" and c.source_type = 0 or c.source_type = 9 order by a.guid, c.id, c.link
保存为一个视图,命名为smartai_extra
重构过程
guid,.go creature id
entry,通过工具(editor)查看AI过程
id,区分不同的AI过程
link,一个事件对应多个动作
event_type, action_type, target_type为了方便研究具体AI过程
三张表逻辑关系的整理
排序,先罗列某个怪物的所有AI,id,link排序的目的,主要了解AI过程的优先级
举例1:格拉克-洛克鲁布(事件链)
使用SAI的怪物的具体案例
guid=10,entry=9520
研究依赖GM
.learn 40733
.learn 5384
.go creature guid
研究目标:血量百分比事件
血量变更做代码埋点(血量变更的代码涉及很多对象,不是每一个都需要百分比检测事件,所以不选择这里)
定时来检测血量百分比(我们选择这个)
1 2 3 4 5 6 7 8 9 10 11 12 13 select * from smart_scripts where entryorguid= 9520 ;select action_type, action_param1 from smart_scripts where entryorguid = 9520 and id >= 5 and id <= 8 ;
gm测试下怪物ai效果1 2 3 4 5 6 7 8 9 # 聊天窗gm .go creature 10 .gm off .damage 20000 # 格拉克-洛克鲁布屈服了,并且脱战 .learn 14250 # 学习捕捉格拉克技能 .gm off # 继续攻击它 # 释放技能 # 格拉克:想玩玩嘛,那就来吧
举例2:血槌苦力(附加事件条件)
使用SAI的怪物的具体案例
guid=154,entry=21238
依赖GM
.die 直接杀死敌方
.damage health 给怪物造成伤害
研究目标:进入战斗事件以及条件模块的实现
进入战斗事件:怪物仇恨列表和战斗列表
条件模块:
conditions.SourTypeOrReferenceId = 22 说明是smart_scripts中的条件
SourceEntry对应smart_scripts中的entryorguid
SourceGroup对应smart_scripts中的id+1,说明是哪个ai过程中的条件
可以配置多个AI过程中的条件,并且一个AI过程可以配置多个条件
vector<Condition*>ConditionContainer; // 条件容器
map<uint32/*SourceEntry*/, ConditionContainer>ConditionsByEntryMap; // 怪物类型和条件容器的对应关系
map<uint32, ConditionsByEntryMap>ConditionEntriesByCreatureIdMap; // 具体的怪物对应的多个类型和条件的对应关系
1 2 3 4 5 6 7 select * from smartai_extra where event_type = 4 ; select * from smart_scripts where entryorguid = 21238 ; select * from conditions where SourceTypeOrReferenceId = 22 and SourceEntry = 21238 ;
到WoWDatabaseEditor中查看21238这个怪物的AI
解析
死亡的时候,介入接了某个任务,会说一句话
进入战斗的时候35%会说一句话
每30s释放35918-刺破护甲这个技能
当生命小于30%时释放8599-激怒这个技能,冷却35s-45s
1 2 3 4 5 6 # 聊天窗口gm .quest add 11000 # 给自己添加11000这个任务 .go creature 154 # 去到怪物身边 .gm off # 关闭gm .gm on .die # 查看死亡之后的AI
举例3:诺格(NPC与NPC的AI交互)
使用SAI的怪物的具体案例
guid=4672,entry=3412
研究依赖GM
.quest add 任务id
.quest remove 任务id
研究目标:AI之间的交互(Event_SetData->Action_DataSet)
不仅仅是解决SAI和SAI之间的交互
同时也解决了SAI和ScriptedAI之间的交互
交互流程
A怪物发起动作:SMART_ACTION_SET_DATA
B怪物响应事件:SMART_EVENT_DATA_SET
可以发起多个set_data,同时也可以响应多个data_set事件
1 2 3 4 5 6 7 8 9 10 select * from smart_scrpits where action_type= 45 and source_type= 0 and entryorguid > 0 ;select * from creature where id = 3412 ;select * from smart_scrpits where entryorguid = 3412 ;
1 2 3 4 5 6 # 聊天gm # 必须是部落的种族 .levelup 50 # 需要45及才能接任务 .go creature 4672 # 传递到旁边 # 接任务:设备之战 # 旁边的npc索维克:XX,如果你想去诺莫瑞根,那就和我谈谈
举例4:血帆术士(状态机)
使用SAI的怪物的具体案例
guid=949,entry=1564
研究依赖
event_phase_mask
=0,在所有阶段都会响应事件触发
“>0”, 只有ai处于当前阶段才会响应事件
状态机状态切换事件
SMART_EVENT_EVENT_PHASE_CHANGE
切换状态机的动作
SMART_ACTION_SET_EVENT_PHASE 设置阶段
SMART_ACTION_INC_EVENT_PHASE 累加阶段
SMART_ACTION_RANDOM_PHASE 枚举随机阶段
SMART_ACTION_TYPE_RANDOM_PHASE_RANGE 范围随机阶段
提供十二个阶段的设置
研究目标:SAI状态机的实现
实现不同阶段AI的管理
实现多个AI分支
实现不同AI阶段
只会响应当前阶段的事件
血帆术士案例
多个血帆术士拥有两种不同的AI
一种是召唤魅魔
一种是召唤宠物
1 2 3 4 5 6 7 select * from smartai_extra where action_type= 31 order by entry;select * from smart_scripts where entryorguid= 1564 ;select * from smartai_extra where entry = 1564 ;
1 2 3 4 5 6 # gm 聊天 .go creature 949 # 血帆术士这个怪物 # 当出生的时候,会随机1或2状态 # 1状态 释放技能8722 召唤魅魔 # 2状态 释放技能11939 召唤小鬼
举例5:克朗-石蹄(延迟动作列表)
使用SAI的怪物的具体案例
guid=30682,entry=4895
研究目标:延迟动作列表
延迟动作列表封装了一系列的动作,并视为一个整体,作为一个动作
延迟动作列表中的动作特征为,可进行延迟执行
与id,link的区别:
id,link也是配置一个事件触发一系列动作
timed_actionlist配置一个事件触发一些系列的延迟事件
延迟动作列表通常用来实现剧情
延迟动作列表是序列执行的
与延迟动作列表不同的是smart_scripts,没有先后次序,哪个事件先触发,先去执行对应的AI过程
序列执行就是一个一个执行
guid=26902,entry=3063
研究目标:SAI交互与延迟动作列表综合应用
可以配置多个延迟动作列表
延迟动作列表通过source_type=9与正常怪物AI过程配置不一样(source_type=0)
延迟动作列表entryorguid=entryorguid*100 + 00,01,02
延迟动作列表开启
SMART_ACTION_CALL_TIMED_ACTIONLIST:开启具体某个延迟动作列表
SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST:在多个动作列表中随机一个
SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST:在范围内随机一个
工作流程
smart_scripts中读取具体动作列表
选中动作列表中第一个动作开始,并且初始化定时器
定时任务触发,开始选中第二个动作,并初始化定时器
依次类推
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 select * from smart_scripts where action_type= 80 and source_type= 0 and entryorguid> 0 order by entryorguid;select * from smartai_extra where entry = 4895 ;select * from smart_scripts where entryorguid = 4895 ;select * from smart_scripts where entryorguid = 489500 ;select * from smartai_extra where entry = 3063 ;select * from smart_scripts where entryorguid = 3063 ;select * from smart_scripts where entryorguid = 306300 ;select * from smart_scripts where entryorguid = 306301 ;
1 2 3 4 5 6 7 # gm 聊天 .go creature 30682 # 微笑的吉姆,等待45s-60s # 每5s吉姆会说一句话,共说4句话 .go creature 26902 # 演绎一段很复杂的剧情
2024-07-03
该篇文章被 Cleofwine
归为分类:
Game