Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统

作者: 深蓝色右手  来源: 博客园  发布时间: 2011-04-19 11:18  阅读: 1282 次  推荐: 0                   原文链接   [收藏]  

  谈到人工智能(AI),这个话题就太大了;大学里有《人工智能教程》专门讲这方面的知识,什么大名鼎鼎的人工神经网络、遗传算法等等均可一窥究竟,这里如赘述似乎有些班门弄斧,我们暂且丢它一边去吧。

  本节,我的主要目的是与大家共同探讨AI在RPG游戏中的应用。看过之前教程的朋友一定不会陌生,A*算法就是其中的一个重要组成部分;而本系列Demo中则使用了更为高级的改进型A*算法,不仅优化了性能,同时也大幅提升了玩家的操控体验。除此之外,AI更常见于RPG游戏中的角色,接下来我将引领大家循着AI的足迹,逐步探寻Silverlight网页游戏中的AI系统设计与Demo实现。

  以一份网上见到的AI系统设计文档作为开始,我们不妨首先分析下它的主体思路,大可断定其为直观的解析当前国内即时类MMORPG主流角色AI设计:以古老而传统的有限状态机FSM(Finite State Machine)固定决策树AI为原型,简单而直接。当然,为了让游戏体验更加有趣且不至于显得一成不变,我会考虑引入基于Random的各类概率机制,即使用随机性和灵活性更强一些的模糊状态机FuSM(Fuzzy State Machine)。所有非控角色的行为完全无规律可循难道不会更吸引人吗?

  有了大体思路后,接下来我们要做的就是将复杂而庞大的AI系统简化,使之更好理解并最终转化成Silverlight游戏程序代码。纵横剖析,我更青睐于按照策略AI (tactic)与行为AI (action)两部分予以划分。所谓“策略AI”即角色何时采取何种决策,而“行为AI”则为角色按决策执行何种行动。

  基于以上方案,我首先在角色控件的内部添加一个计时器用于AI逻辑循环,其中策略AI间隔3秒执行一次,用于敌对角色的搜捕(索敌);行为AI与角色动作切帧率同步,根据实时情判断应该执行警戒/追击/攻击/转向/逃逸/或其他等行动;而这两种AI在角色控件中分别对应两个事件,对于主角来说,玩家的操作已相当于主角的策略,因此主角只需注册行为AI事件,而其他非控角色则需要同时兼具两者以具备完整的AI能力:

/// <summary>
/// 动作(帧)切换时触发
/// </summary>
public event EventHandler ActionTrigger; /// <summary>
/// 以1秒为基础单位的时间间隔触发器
/// </summary>
public event EventHandler<IntervalTriggerArgs> IntervalTrigger; /// <summary>
/// 间隔触发器参数
/// </summary>
public class IntervalTriggerArgs : EventArgs {
public int Count { get; set; }
} int tickCount = 0;
IntervalTriggerArgs intervalTriggerArgs = new IntervalTriggerArgs();
void intervalTrigger_Tick(object sender, EventArgs e) {
intervalTriggerArgs.Count = tickCount;
if (IntervalTrigger != null) { IntervalTrigger(this, intervalTriggerArgs); }
tickCount = tickCount == Int32.MaxValue ? 0 : tickCount + 1;
}

接下来又是一个难题,我们该如何编写这两类AI?困惑时不妨借鉴一下前辈们的经验,尝试回忆一下小时候玩过的那些RPG游戏:有的游戏喜欢以复杂程度来定义怪物的AI,打个比方:

  简单AI:角色搜索目标 -> 攻击 -> 频死时回血、逃跑

  中级AI:寻找最近目标 -> 攻击 -> 半血逃逸,呼叫同伴协助

  高级AI:检索周围状况 -> 寻找最弱目标 -> 呼叫同伴,集体攻击

  以上仅仅是一个粗略的AI流程图,然而却生动而有趣的比拟了目前网游大同小异的AI设计规律。或许其中的一些环节仍可被细分成若干枝节,同时有的还会根据游戏本身功能不断的进行拓展;万变不离其宗,性能与趣味性兼具的AI设计总是倍受玩家们迷恋。

  又如《博德之门》、《冰风谷》等龙与地下城类型经典游戏,其中的角色在创建时会根据善恶与种族的选择决定性格,而性格往往就用于确定角色在游戏中的策略AI与行为AI。

  到此,角色AI逻辑编写的切入点已清晰显露。综合以上所有,相信您的思维也一样会变得豁然开朗。接下来在本系列教程Demo的基础上进行代码编写便是非常轻松的事:

/// <summary>
/// 策略AI
/// </summary>
public enum TacticAIs {
/// <summary>
/// 目标主角
/// </summary>
GoalLeader = 0,
/// <summary>
/// 自由战斗
/// </summary>
FreeFighting = 1,
/// <summary>
/// 小组作战
/// </summary>
TeamAttack = 2,
/// <summary>
/// 门派对阵
/// </summary>
MartialBattle = 3
} /// <summary>
/// 行为AI
/// </summary>
public enum ActionAIs {
/// <summary>
/// 简单
/// </summary>
Simple = 0,
/// <summary>
/// 机敏
/// </summary>
Alertness = 1,
/// <summary>
/// 固执
/// </summary>
Persistent = 2,
/// <summary>
/// 怯懦
/// </summary>
Cowardice = 3,
} /// <summary>
/// 角色策略判定
/// </summary>
void role_TacticDecide(object sender, IntervalTriggerArgs e) {
//每间隔3秒执行一次策略检索
if (e.Count % 3 == 0) {
RoleBase role = sender as RoleBase;
//异步判断角色是否处于屏幕显示区域中,是的话且无目标则进行索敌判断:在视线范围内则追击,否则警戒
this.Dispatcher.BeginInvoke(() => {
space.SetSpriteVisible(role, role.InSight(leader));
if (role.Target == null && role.IsVisible) {
bool targetFound = false;
switch (role.TacticAI) {
case TacticAIs.GoalLeader:
if (role.Target == null && role.IsVisible) {
if (role.IsHostileTo(leader) && leader.InCircle(role.Position, role.SightRange)) {
role.Target = leader;
targetFound = true;
}
}
break;
case TacticAIs.FreeFighting:
int count = 0;
int roleNum = space.AllRoles().Count;
while (count < roleNum) {
RoleBase target = space.AllRoles()[ObjectBase.RandomSeed.Next(roleNum)];
if (role.IsHostileTo(target) && target.InCircle(role.Position, role.SightRange)) {
role.Target = target;
targetFound = true;
break;
}
count++;
}
break;
case TacticAIs.TeamAttack:
for (int i = space.AllRoles().Count - 1; i >= 0; i--) {
RoleBase target = space.AllRoles()[i];
if (role.IsHostileTo(target) && target.InCircle(role.Position, role.SightRange)) {
role.Target = target;
targetFound = true;
break;
}
}
break;
case TacticAIs.MartialBattle:
count = 0;
roleNum = space.AllRoles().Count;
while (count < roleNum) {
RoleBase target = space.AllRoles()[ObjectBase.RandomSeed.Next(roleNum)];
if (role.IsHostileTo(target) && role.Profession != target.Profession && target.InCircle(role.Position, role.SightRange)) {
role.Target = target;
targetFound = true;
break;
}
count++;
}
break;
}
if (!targetFound) { role.Guard(role.Position); }
}
});
}
} /// <summary>
/// 角色行为执行
/// </summary>
void role_ActionDecide(object sender, EventArgs e) {
RoleBase attacker = sender as RoleBase;
RoleBase target = attacker.Target;
if (attacker.IsHostileTo(target) && attacker.IsVisible) {
//怯懦行为简单表现为不主动追击,发现被攻击时立刻逃跑
if (target.ActionAI == ActionAIs.Cowardice) {
target.Target = null;
target.MoveTo(new Point(ObjectBase.RandomSeed.Next((int)(target.Position.X - target.SightRange), (int)(target.Position.X + target.SightRange)), ObjectBase.RandomSeed.Next((int)(target.Position.Y - target.SightRange), (int)(target.Position.Y + target.SightRange))));
}
if (target.InCircle(attacker.Position, attacker.AttackRange)) {
attacker.TurnTowardsTo(target.Position);
attacker.Attack();
//机智行为简单表现为受到攻击时会反击,受到两个以上敌人同时攻击时将会试图逃离现场
if (target != leader) {
if (target.ActionAI == ActionAIs.Alertness) {
if (target.Target != null) {
target.Target = null;
target.MoveTo(new Point(ObjectBase.RandomSeed.Next((int)(target.Position.X - attacker.SightRange), (int)(target.Position.X + attacker.SightRange)), ObjectBase.RandomSeed.Next((int)(target.Position.Y - attacker.SightRange), (int)(target.Position.Y + attacker.SightRange))));
} else {
target.Target = attacker;
}
}
}
} else if (target.InCircle(attacker.Position, attacker.SightRange) || attacker.ActionAI == ActionAIs.Persistent) {
//固执行为简单表现为抓住一个目标一直追击,直至自己或目标死亡为止
attacker.MoveTo(new Point(ObjectBase.RandomSeed.Next((int)(target.Position.X - attacker.AttackRange), (int)(target.Position.X + attacker.AttackRange)), ObjectBase.RandomSeed.Next((int)(target.Position.Y - attacker.AttackRange), (int)(target.Position.Y + attacker.AttackRange))));
} else {
attacker.Target = null;
attacker.Stop();
}
}
}

随手写下数十行代码,非常非常简单,外行人都能看得出不外乎if/else/switch/case/random,然而却实现了4种策略 + 4种行为,外带上角色职业与参数的不同将产生至少20多种不同的AI组合搭配,更重要的是非常易于新功能的拓展与维护。没错,Silverlight开发游戏就是这样简单~,让我们一同来领略下Silverlight为网游开发所带来的革命性奇迹吧(在线演示地址http://silverfuture.cn/)!

  当然,这些所有的效果也仅仅算作是AI的入门;类似仿真技术的角色AI最早出现于欧美网游大作中,比如基于仇恨系统的角色索敌AI,经典代表作便是大家游耳熟能详的《无尽的任务》(EQ)。这类游戏的AI系统设计通常以“仇恨值”最高的敌对阵营角色确定为攻击对象,所有角色的仇恨值都储存于一个动态表/库中随时检索。仇恨值的程度又与很多因素相关联,比如距离远近、等级差距、所剩生命值多少、是否在施展“嘲讽”等挑衅技能、当前行为状态(冥想/步行/跑动)、是否正在屠杀同族、时间流逝等等,且每个要素的权重值也不同,国内网游通常都喜欢将距离远近定为最高权重。当AI启动时会对同一区域内所有对象进行以上数据的统和,仇恨值得分最高的角色将被视为最有价值攻击对象,且仇恨值往往会被持续累积,直到角色死亡或施展特殊技能比如假死后方回到原点。当然,仇恨值的累积也并非都是简单的1+1,对同一怪物连续施展3次火球术将会彻底将其惹毛,没错,你太小看它了,它真的很生气;是的,游戏技术一直以来都在模仿真实的人类世界,试想下如果你被某人不小心踩上一脚相比被其连续踩上三脚我相信这样的愤怒不仅仅是简单的3倍加成吧?当你把生活中的类似环境置位到游戏中的角色AI时,你会觉得其实游戏设计原来是件多么有趣的事情。

  追求高仿真虚拟现实的大型游戏甚至愿意花费超过20%的CPU以处理逼真的角色AI逻辑,其中往往包含着复杂的人工神经网络和遗传算法;当然对于更强调操控与实战效果的网游来说,AI不需要太复杂,但是性效比该如何取舍也必定是一个值得仔细斟酌考量的环节。Silverlight 5即将发布了~,带着超强大的功能与无限喜悦,我由衷期待!!

  本节源码请到目录中下载。

  在线演示地址:http://silverfuture.cn

Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统的更多相关文章

  1. Silverlight 2.5D RPG游戏技巧与特效处理:(五)HLSL渲染动画

    原文:Silverlight 2.5D RPG游戏技巧与特效处理:(五)HLSL渲染动画 或许大家依旧对上一节中的“黑夜”及“梦回过去”记忆犹新,追问下去HLSL到底是何方神圣能实现如此炫酷之效果?层 ...

  2. 如何制作一款HTML5 RPG游戏引擎——第五篇,人物&人物特效

    上一次,我们实现了对话类,今天就来做一个游戏中必不可少的——人物类. 当然,你完全是可以自己写一个人物类,但是为了方便起见,还是决定把人物类封装到这个引擎里. 为了使这个类更有意义,我还给人物类加了几 ...

  3. HTML5 RPG游戏引擎 地图实现篇

    一,话说全国年夜事   前没有暂看到lufy的专客上,有一名伴侣念要一个RPG游戏引擎,出于兴趣筹办入手做一做.因为我研讨lufylegend有冶时间了,对它有必然的依赖性,因而便筹办将那个引擎基于 ...

  4. 如何制作一款HTML5 RPG游戏引擎——第一篇,地图类的实现

    一,话说天下大事 前不久看到lufy的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做.由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于lufy ...

  5. 【开源】使用Angular9和TypeScript开发RPG游戏

    RPG系统构造 通过对于斗罗大陆小说的游戏化过程,熟悉Angular的结构以及使用TypeScript的面向对象开发方法. 项目地址 人物 和其他RPG游戏类似,游戏里面的人物角色大致有这样的一些属性 ...

  6. unity3d 游戏插件 溶解特效插件 - Dissolve Shader

    unity3d 游戏插件 溶解特效插件 - Dissolve Shader   链接: https://pan.baidu.com/s/1hr7w39U 密码: 3ed2

  7. 【android原生态RPG游戏框架源码】

    转载请注明原创地址:http://www.cnblogs.com/zisou/p/android-RPG.html 这份源码是在今年6月份写的,当时公司有一个技术部们的学习讨论的讲座,然后我自己就写了 ...

  8. RPG JS:免费开源的跨平台RPG游戏引擎

    RPG JS是一个2D RPG游戏制作引擎,目前版本基于Ease|JS游戏引擎,基于Canvas Engine的新版本即将发布. RPG JS是免费且开源的. RPG JS有着完善的文档支持. RPG ...

  9. RPG游戏学习——1.任务脚本系统

    [前言] 近期准备做个rpg小游戏,所以開始研究rpg的一些系统.rpg最核心的应该是任务脚本系统(其它脚本系统类似),在參考了非常多网上的资料后,简要总结例如以下. [脚本的触发运行] 一个脚本须要 ...

随机推荐

  1. Linux nginx安装步骤 centos7

    1.安装依赖: yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 2.创建一个文件夹cd /usr/localmk ...

  2. vscode如何配置debug,python正则表达式如何匹配括号,关于python如何导入自定义模块

    关于vscode如何配置debug的问题: 1.下载安装好python,并且配置好 环境变量 2.https://www.cnblogs.com/asce/p/11600904.html 3.严格按照 ...

  3. Log4j不写入日志文件排错记录

    背景: 之前用 log4j一直设置的输出到控制台.今天由于job任务出现了异常,因为是异步的,没办法在控制台看错误信息了,于是乎决定把日志打印到文件里面.然后就找了篇博客配置了下.但是配置完后,怎么也 ...

  4. NodeMCU入坑指南-烧写固件并连接WIFI

    写在前面 今天入手了一个NodeMCU的板子,准备学习一下物联网相关的知识.不过由于博主学艺不精,在第一步烧写固件上就踩坑了,所以就想着把自己的踩坑经历写出来分享给大家,希望能有一些帮助~ 材料准备 ...

  5. HDU-1251 统计难题(我就是不用字典树)

    统计难题 ?戳这里可以前往原题 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为 ...

  6. Building Applications with Force.com and VisualForce(Dev401)(十四):Implementing Business Processes:Auditing Processes

    Dev401-015:Implementing Business Processes:Auditing Processes Module Objectives1.list some of the fe ...

  7. 一份从入门到精通NLP的完整指南 | NLPer

    该小博主介绍 本人:笔名zenRRan,方向自然语言处理,方法主要是深度学习. 未来的目标:人工智能之自然语言处理博士. 写公众号目的:将知识变成开源,让每个渴求知识而难以入门人工智能的小白以及想进阶 ...

  8. Python第七章-面向对象高级

    面向对象高级 一. 特性 特性是指的property. property这个词的翻译一直都有问题, 很多人把它翻译为属性, 其实是不恰当和不准确的. 在这里翻译成特性是为了和属性区别开来. 属性是指的 ...

  9. html-css:浮动_清除浮动

    1.浮动 清除浮动之前我们首先需要了解为什么要清除浮动 1. 假设我们有一个父盒子,不设置高度,其高度有内部子盒子的大小自动撑开,这样是完全可行的,因为有时候我们并不想直接固定死父盒子的大小,而是根据 ...

  10. coding++:Java读写到览器Cookies中

    首先我们认识下什么是cookies: cookie实际上是一个存在你硬盘里的数据,但是这些数据很特殊,只能由web应用提交给浏览器帮助存储,并且我们还能读取浏览器存在本地的cookie web应用一般 ...