文章目录

  • 简介
  • 什么是集群AI?
  • RimWorld源码中有没有一个节点用于集群AI?
  • 职责节点
  • 集群AI如何与职责节点联系?
  • 集群AI
  • LordToil与Toil的关系?
  • 集群AI的状态机

简介

相信看过上一章关于AI的介绍,你应该对行为树的基础知识有一些了解,并且知道游戏中角色AI是基于行为树实现的。在这一章我会简单介绍一些集群AI是如何工作的。

什么是集群AI?

集群AI听起来好像很复杂,实际上集群AI就是一群角色使用同一个AI而已。
创建一个行为节点的实例,想办法让一群角色当前执行这个节点实例,这样就实现了集群AI。

RimWorld源码中有没有一个节点用于集群AI?

有的,RW中有一棵额外的行为树叫做“LordDuty”,其中一个被挂载的节点是“ThinkNode_JoinVoluntarilyJoinableLord”,具有很高的优先级

我们找到这颗行为树,会发现上面有个名字叫做 “ThinkNode_Duty”的节点,集群AI的实现就依赖于这个节点。这个节点涉及一套职责系统来动态改变AI,集群AI只是职责系统的其中一部分功能。

职责节点

职责节点遍历了整个数据库中的职责定义数据,将每个职责对应的行为树作为子节点挂载在职责节点上。也就是说职责节点在运行时会拥有全部的职责定义中的行为树实例。然后会尝试根据角色当前的职责来分配对应职责的行为。

using System;
using Verse;
using Verse.AI;
using Verse.AI.Group;namespace RimWorld
{// Token: 0x02000E3F RID: 3647public class ThinkNode_Duty : ThinkNode{// Token: 0x060052AB RID: 21163 RVA: 0x001BF624 File Offset: 0x001BD824public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParams){if (pawn.GetLord() == null){Log.Error(pawn + " doing ThinkNode_Duty with no Lord.", false);return ThinkResult.NoJob;}if (pawn.mindState.duty == null){Log.Error(pawn + " doing ThinkNode_Duty with no duty.", false);return ThinkResult.NoJob;}return subNodes[pawn.mindState.duty.def.index].TryIssueJobPackage(pawn, jobParams);}// Token: 0x060052AC RID: 21164 RVA: 0x001BF69C File Offset: 0x001BD89Cprotected override void ResolveSubnodes(){foreach (DutyDef dutyDef in DefDatabase<DutyDef>.AllDefs){//处理每一个职责定义的节点和子节点dutyDef.thinkNode.ResolveSubnodesAndRecur();//将所有职责中的节点设置为当前节点的子节点this.subNodes.Add(dutyDef.thinkNode.DeepCopy());}}}
}

基类方法

/// <summary>
/// 对自身和所有字节点调用ResolveSubnodes
/// </summary>
public void ResolveSubnodesAndRecur()
{if (this.uniqueSaveKeyInt != -2){return;}this.ResolveSubnodes();for (int i = 0; i < this.subNodes.Count; i++){this.subNodes[i].ResolveSubnodesAndRecur();}
}

集群AI如何与职责节点联系?

很简单,集群AI拥有一组受其控制的角色,遍历所有的角色,将他们的职责设定为集群AI的职责,之后由于职责节点的高优先级,所有的角色会优先执行同样的行为。

集群AI

说了半天还没有见到集群AI的模块,集群AI在RW种是以“Lord”命名的。
首先要明确一点,集群AI和行为树不一样,集群AI是需要的时候动态生成的,而不是一开始就配置在角色身上的。所以你可能会在事件中看到集群AI的生成,比如袭击事件。

/// <summary>
/// 创建集群AI
/// </summary>
/// <param name="parms"></param>
/// <param name="pawns"></param>
public virtual void MakeLords(IncidentParms parms, List<Pawn> pawns)
{Map map = (Map)parms.target;//分组List<List<Pawn>> list = IncidentParmsUtility.SplitIntoGroups(pawns, parms.pawnGroups);int @int = Rand.Int;//每一组生成一个集群AIfor (int i = 0; i < list.Count; i++){List<Pawn> list2 = list[i];//生成集群AI 设置目标为list2Lord lord = LordMaker.MakeNewLord(parms.faction, this.MakeLordJob(parms, map, list2, @int), map, list2);lord.inSignalLeave = parms.inSignalEnd;QuestUtility.AddQuestTag(lord, parms.questTag);if (DebugViewSettings.drawStealDebug && parms.faction.HostileTo(Faction.OfPlayer)){Log.Message(string.Concat(new object[]{"Market value threshold to start stealing (raiders=",lord.ownedPawns.Count,"): ",StealAIUtility.StartStealingMarketValueThreshold(lord)," (colony wealth=",map.wealthWatcher.WealthTotal,")"}), false);}}
}

集群AI的工作模式与AI的工作模式类似,集群AI有一个LordJob,LordJob对应N个LordToil,和Job,Toil的机制很相似。不同的是,LordJob的流程不像Job一样按顺序执行。
在上一章我有介绍过,游戏AI的实现基本使用行为树或状态机。而LordJob的流程是一套状态机的系统。他可以在任意流程之间跳转。行为树有一个缺点就是必须按顺序执行,而与状态机混搭的方式可以规避掉这个缺点。

/// <summary>
/// 创建集群AI工作
/// </summary>
/// <param name="parms"></param>
/// <param name="map"></param>
/// <param name="pawns"></param>
/// <param name="raidSeed"></param>
/// <returns></returns>
protected override LordJob MakeLordJob(IncidentParms parms, Map map, List<Pawn> pawns, int raidSeed)
{//事件中心或第一个角色的坐标IntVec3 originCell = parms.spawnCenter.IsValid ? parms.spawnCenter : pawns[0].PositionHeld;//事件派系与玩家敌对if (parms.faction.HostileTo(Faction.OfPlayer)){//突击殖民者return new LordJob_AssaultColony(parms.faction, true, true, false, false, true);}//非敌对派系 比如动物 尝试在殖民地外寻找随机点突袭IntVec3 fallbackLocation;RCellFinder.TryFindRandomSpotJustOutsideColony(originCell, map, out fallbackLocation);return new LordJob_AssistColony(parms.faction, fallbackLocation);
}

LordToil与Toil的关系?

每个LordJob对应N个LordToil,也就是集群AI的工作流程之一。而LordToil会对应一个Duty职责,从而对应了一颗行为树。一颗行为树上可能有M个节点对应Job,每个节点有K个流程Toil。所以一个LordJob上可能涉及NMK个Toil。

集群AI的状态机

举个复杂的例子,突袭的集群AI,突袭的集群AI包含,突袭、绑架、偷窃、工兵、离开等集群流程。
“stateGraph ”就是LordJob生成的状态机。添加全部流程后,还需要添加某两个流程之间的跳转和触发跳转的条件。 至于集群突袭流程具体就不详细介绍了,突袭Action节点很复杂,仅是寻找合适的目标就有大概300行代码,有兴趣的自己看看。
突袭流程优先级最高的节点并不是突袭节点,而是服用化学增强药物。当集群AI组内受伤人数达到一定数量时,组内角色就会尝试服用药物。

/// <summary>
/// 创建状态图
/// </summary>
/// <returns></returns>
public override StateGraph CreateGraph()
{var stateGraph = new StateGraph();LordToil lordToil = null;//工兵流程if (sappers){//工兵行为流程lordToil = new LordToil_AssaultColonySappers();//使用智能躲避格子if (useAvoidGridSmart){lordToil.useAvoidGrid = true;}//加入状态图stateGraph.AddToil(lordToil);//过渡var transition = new Transition(lordToil, lordToil, true);//触发器 角色丢失transition.AddTrigger(new Trigger_PawnLost());//添加过渡stateGraph.AddTransition(transition);}//突击行为流程LordToil lordToil2 = new LordToil_AssaultColony();if (useAvoidGridSmart){lordToil2.useAvoidGrid = true;}stateGraph.AddToil(lordToil2);//离开地图流程var lordToilExitMap = new LordToil_ExitMap(LocomotionUrgency.Jog, false, true){useAvoidGrid = true};stateGraph.AddToil(lordToilExitMap);if (sappers){//过渡 工兵流程 到 突击流程var transition2 = new Transition(lordToil, lordToil2);//触发器 不存在作战工兵transition2.AddTrigger(new Trigger_NoFightingSappers());stateGraph.AddTransition(transition2);}//突击者派系是类人派系if (assaulterFaction.def.humanlikeFaction){//可以超时或逃离if (canTimeoutOrFlee){//过渡 突击流程 到 离开地图流程var transition3 = new Transition(lordToil2, lordToilExitMap);//工兵流程存在if (lordToil != null){//储存工兵流程transition3.AddSource(lordToil);}//添加过渡触发器 超时 transition3.AddTrigger(new Trigger_TicksPassed(sappers? SapTimeBeforeGiveUp.RandomInRange: AssaultTimeBeforeGiveUp.RandomInRange));//触发前回调transition3.AddPreAction(new TransitionAction_Message("MessageRaidersGivenUpLeaving".Translate(this.assaulterFaction.def.pawnsPlural.CapitalizeFirst(),this.assaulterFaction.Name), null, 1f));stateGraph.AddTransition(transition3);//过渡 突击流程 到 离开地图流程var transition4 = new Transition(lordToil2, lordToilExitMap);if (lordToil != null){transition4.AddSource(lordToil);}//伤害承受比例 取0.25到0.35随机数var floatRange = new FloatRange(0.25f, 0.35f);var randomInRange = floatRange.RandomInRange;//触发器 达到承受比例 或超过900点transition4.AddTrigger(new Trigger_FractionColonyDamageTaken(randomInRange, 900f));//突击者造成破坏 心满意足离开transition4.AddPreAction(new TransitionAction_Message("MessageRaidersSatisfiedLeaving".Translate(assaulterFaction.def.pawnsPlural.CapitalizeFirst(),assaulterFaction.Name)));stateGraph.AddTransition(transition4);}//允许绑架if (canKidnap){var startingToil = stateGraph.AttachSubgraph(new LordJob_Kidnap().CreateGraph()).StartingToil;var transition5 = new Transition(lordToil2, startingToil, false, true);if (lordToil != null){transition5.AddSource(lordToil);}transition5.AddPreAction(new TransitionAction_Message("MessageRaidersKidnapping".Translate(this.assaulterFaction.def.pawnsPlural.CapitalizeFirst(),this.assaulterFaction.Name), null, 1f));transition5.AddTrigger(new Trigger_KidnapVictimPresent());stateGraph.AddTransition(transition5, false);}//允许偷窃if (canSteal){var startingToil2 = stateGraph.AttachSubgraph(new LordJob_Steal().CreateGraph()).StartingToil;//过渡 突击 到 偷窃var transition6 = new Transition(lordToil2, startingToil2, false, true);if (lordToil != null){transition6.AddSource(lordToil);}transition6.AddPreAction(new TransitionAction_Message("MessageRaidersStealing".Translate(this.assaulterFaction.def.pawnsPlural.CapitalizeFirst(),this.assaulterFaction.Name), null, 1f));//触发方式 有高价值物品在附近 300个tick内集群无成员受伤transition6.AddTrigger(new Trigger_HighValueThingsAround());stateGraph.AddTransition(transition6, false);}}//过渡 突击流程 到 离开地图流程var transition7 = new Transition(lordToil2, lordToilExitMap, false, true);if (lordToil != null){transition7.AddSource(lordToil);}//触发方式 阵营关系变为非敌对transition7.AddTrigger(new Trigger_BecameNonHostileToPlayer());transition7.AddPreAction(new TransitionAction_Message("MessageRaidersLeaving".Translate(this.assaulterFaction.def.pawnsPlural.CapitalizeFirst(), this.assaulterFaction.Name),null, 1f));stateGraph.AddTransition(transition7, false);return stateGraph;
}

Rimworld Mod制作教程12 集群AI机制介绍相关推荐

  1. Rimworld Mod制作教程1 认识Mod结构

    文章目录 废话 核心内容 1 认识mod结构 1.1 mod结构 2 认识开发工具 2.1 开发工具 2.2 visual studio开发环境 2.3 程序集构建 2.4 修改编译输出路径 2.5 ...

  2. Rimworld Mod制作教程3 使用Xpath制作patch(补丁)

    文章目录 废话 核心内容 1 使用Xpath制作patch(补丁) 1.1 基本格式 1.2 手术类型 1.3 ~~偷窥~~ 参考他人代码 废话 rimworld在A17版本后提供了一个新的编写mod ...

  3. Rimworld Mod制作教程2 创建数据定义

    文章目录 废话 核心内容 1 创建数据定义 1.1 定义一个新的抽象物品 手办基类 1.2 源源不断的手办(Garage Kid) 1.3 新材料(Stuff) 1.4 添加配方(Recipe) 1. ...

  4. 上树建站教程:新手单页网站制作教程上集

    功能强大. 链接.文件下载等功能,一份源程序可以制造出无数个网站,只需一些超级简单的 页面程序可以随意的编辑.修改,包括:图片.文案.背景.图片滚动  单页型网站:就是一个独立页面的网站,是一个纯HT ...

  5. 【饥荒mod制作吧第四篇】mod制作教程系列

    直奔主题算了! [1]吧内教程 第一部分: @XWJ249  毕竟教程基本都是他做的. 2016丨4-14丨[索引]我的mod教程 http://tieba.baidu.com/p/448580475 ...

  6. 【Hadoop生态圈】1.Hadoop入门教程及集群环境搭建

    文章目录 1.简介 2.环境准备 3.安装hadoop 3.修改Hadoop配置文件 3.1.hadoop-env.sh配置 3.2.core-site.xml配置 3.3.hdfs-site.xml ...

  7. SLES 12集群图形配置新界面——抢先版

      前言:各位广大的SLES忠实粉丝们,以下是SLES 12的集群管理工具的简单概述,供大家了解.对与来临的SLES 12,我们都很关注,下面由我先来个"冰山一角"吧!以下是SLE ...

  8. 饥荒mod制作教程--物品(武器)--01

    武器模板(这是一个联机版的mod,要改成单机版的还需要做部分修改): 链接:https://pan.baidu.com/s/1P0lBxVRdQ3oV9VAB1-Kfhg 密码:n2sa 首先确定武器 ...

  9. quartz集群调度机制调研及源码分析---转载

    quartz2.2.1集群调度机制调研及源码分析 引言 quartz集群架构 调度器实例化 调度过程 触发器的获取 触发trigger: Job执行过程: 总结: 附: 引言 quratz是目前最为成 ...

最新文章

  1. AI每日精选:AI可追踪人体血糖水平;中国或成为首个AI超级大国
  2. 自学python找工作难吗-大四应届毕业生,学了两个月Python,找工作感觉好难啊?...
  3. DNN结构演进History—CNN( 优化,LeNet, AlexNet )
  4. Blazor VS 传统Web应用程序
  5. 2018-2019-2 20165212《网络攻防技术》Exp5 MSF基础应用
  6. 21 MM配置-采购-定义采购组
  7. redis五种常见的数据结构
  8. JBOSS 5.0.0GA的集群搭建
  9. 智能优化算法应用:基于麻雀搜索算法PID参数优化 - 附代码
  10. unistd.h中定义函数
  11. Python游戏编程快速上手
  12. 用Vim查看和编辑二进制文件
  13. arduino 读取模拟电压_【Arduino官方教程】基础示例(六):读取模拟电压
  14. 如何做拉新活动?拉新裂变的12种玩法,你学废了没?
  15. 目前得前端框架都有哪些?
  16. 关于Oracle数据库start whith 递归查询的另类认知
  17. SLF4J的高级写法
  18. HackTheBox::Seal
  19. Allegro如何使用Snake命令走蛇形线操作指导
  20. 结构化数据和非结构化数据、半结构化数据的区别-归纳总结整理

热门文章

  1. php如何对mysql加锁_MySQL 加锁处理分析(一)
  2. js日期格式转换Wed Mar 22 13:38:37 CST 2017 转换 为yyyy-mm-dd
  3. 用poi将word表格转excel
  4. Houdini abcobj 导入 Maya
  5. EI收录中国期刊目录 各个版本的含义及收录例子-12年初版
  6. Python 基于tkinter模块的GUI可视化学生成绩管理系统实现(含文件保存)
  7. 导出 Excel 表格
  8. 使用Java在浏览器页面无法导出excel表格
  9. Do Transformers Really Perform Bad for Graph Representation 阅读笔记
  10. Linux无线网连接解决方案