上次提出了关于AI懒惰问题的解决方案(见上一篇),一种称为计时器法,就是通过人为的延时来平滑AI的行为抖动,还有一种称为交叉边界法,通过平滑边际值来解决AI在边际上的行为问题。在讨论的最后,我们看到对于交叉边界法,在结果上看来,稍稍有点不是很符合一开始的对AI的行为定义。
再来看一下这个问题,当红圈从A区域移动到图示中新位置的时候,由于虚拟区域的存在,蓝圈不会移动到D的中心
解决这个问题有多种不同的方案,本来嘛,AI的代码基本上没有什么标准答案,我在这里提出我的一个方案,原本我们定义的虚拟区域是静态的,也就是说,大小是固定不变,如果我们改用一个会随时间变化渐渐缩小的虚拟区域,那就可以很好的解决上面的问题,我们对以前的算法做一个补充:
当红圈从B区域进入A区域时,建一个A的虚拟区域,然后随时间,A的虚拟区域渐渐减小直到和A区域一样大
当红圈从A区域进入B区域时,建一个B的虚拟区域,然后随时间,B的虚拟区域渐渐减小直到和B区域一样大
当红圈在A区域,并且不在B的虚拟区域中时,蓝圈的目标点在C的中心
当红圈在B区域,并且不在A的虚拟区域中时,蓝圈的目标点在D的中心
由于虚拟区域随着时间最终会和原来的区域一样大,所以就不存在以前不符合AI预期行为的问题了。:)
另外,用计时器来控制某些值得变化,是在实践中经常碰到的一个问题,以前经常是用下面的这种方式来做:
if 计时器超时 then
计时器重置
a = 新的值
else
a = 旧的值
end
对于一些有规律,或者重复的东西,自然的就想到是否可以封装一下,用类把一些值定义成所谓的懒惰值(Lazy Value),比如,原本我们对一个布尔值赋值,它的值的变化是“立即的”
bool instantValue = true;
print instantValue; //输出”true”
而现在我们希望对于懒惰值而言,我们可以延迟某个时间来改变他的值
float updateInterval = 20.f;
LazyBool lazyValue(updateInterval, false); //20秒才会更新一次, 默认值是false
…
lazyValue.Set(curGameTime, true); //赋值,传入当前游戏时间
print lazyValue //如果离上一次更改还没到20秒,输出上一次的值,如果超过20秒,输出”true”
有了这样的概念,这个类应该是比较容易实现的,我在我们的AI系统中用模板的的方式实现了这样一个懒惰值类,作为AI经常会用到的工具类收藏在个人的小本本中,:)。
相关:
————————————————————————
作者:Finney
Blog:AI分享站(http://www.aisharing.com/)
Email:finneytang@gmail.com
本文欢迎转载和引用,请保留本说明并注明出处
————————————————————————
如果红圈在AB交界来回穿越,那么AB的虚拟区域都会不断被重置为最大,蓝圈的行为还是不如预期。请问这个问题如何解决呢?
交界区理解反了吧。。
不错,实际开发中也碰到过抖动的问题。考虑的解决方案也是做延时
总结得很不错,做AI时,经常会遇到这个问题:)
是呀,懒惰的问题,不管是在优化还是调整AI上,都很有用