.value_f) {
_open.splice(i, 0, newNode);
break;
}
}
} else {
for (var j:int=__len; j>0; j--) {
//找到比F值大的值,就插在此值之前
if (newNode.value_f>=_open[(j-1)].value_f) {
_open.splice(j, 0, newNode);
break;
}
}
}
//计算开放列表中F平均值
_aveOpen += (newNode.value_f-_aveOpen)/_open.length;
}
}
//取开放列表里的最小值
private function getOpen():Object {
var __next:Object = _open.splice(0,1)[0];
//计算开放列表中F平均值
_aveOpen += (_aveOpen-__next.value_f)/_open.length;
return __next;
}
运行结果如图
我们看到,耗时25毫秒,这个数字虽然不准确的,但是与普通查找算法相比较,速度确实是提高了
3,二叉树查找算法
(参考了火夜风舞的C++新霖花园中的文章)
这个算法可以说是A*算法的黄金搭档,也是被称为苛求速度的binary heap”的方法
就是根据二叉树原理,来维持开启列表的“排序”,这里说的排序只是遵循二叉树的原理的排序而已,即父节点永远比子节点小,就像下面这样
1
| |
5 9
| | |
7 12 10
二叉树每个节点的父节点下标 = n / 2;(小数去掉)
二叉树每个节点的左子节点下标 = n * 2;右子节点下标 = n * 2 +1
注意,这里的下标和它的值是两个概念
//加入开放列表
private function setOpen(newNode:Object,newFlg:Boolean = false):void {
var new_index:int;
if(newFlg){
newNode.open = true;
var new_f:int = newNode.value_f;
_open.push(newNode);
new_index = _open.length - 1;
}else{
new_index = newNode.index;
}
while(true){
//找到父节点
var f_note_index:int = new_index/2;
if(f_note_index > 0){
//如果父节点的F值较大,则与父节点交换
if(_open[new_index].value_f < _open[f_note_index].value_f){
var obj_note:Object = _open[f_note_index];
_open[f_note_index] = _open[new_index];
_open[new_index] = obj_note;
_open[f_note_index].index = f_note_index;
_open[new_index].index = new_index;
new_index = f_note_index;
}else{
break;
}
}else{
break;
}
}
}
//取开放列表里的最小值
private function getOpen():Object {
if(_open.length <= 1){
return null;
}
var change_note:Object;
//将第一个节点,即F值最小的节点取出,最后返回
var obj_note:Object = _open[1];
_open[1] = _open[_open.length - 1];
_open.pop();
_open[1].index = 1;
var this_index:int = 1;
while(true){
var left_index:int = this_index * 2;
var right_index:int = this_index * 2 + 1;
if(left_index >= _open.length){
break;
}else if(left_index == _open.length - 1){
//当二叉树只存在左节点时,比较左节点和父节点的F值,若父节点较大,则交换
if(_open[this_index].value_f > _open[left_index].value_f){
change_note = _open[left_index];
_open[left_index] = _open[this_index];
_open[this_index] = change_note;
_open[left_index].index = left_index;
_open[this_index].index = this_index;
this_index = left_index;
}else{
break;
}
}else if(right_index < _open.length){
//找到左节点和右节点中的较小者
if(_open[left_index].value_f <= _open[right_index].value_f){
//比较左节点和父节点的F值,若父节点较大,则交换
if(_open[this_index].value_f > _open[left_index].value_f){
change_note = _open[left_index];
_open[left_index] = _open[this_index];
_open[this_index] = change_note;
_open[left_index].index = left_index;
_open[this_index].index = this_index;
this_index = left_index;
}else{
break;
}
}else{
//比较右节点和父节点的F值,若父节点较大,则交换
if(_open[this_index].value_f > _open[right_index].value_f){
change_note = _open[right_index];
_open[right_index] = _open[this_index];
_open[this_index] = change_note;
_open[right_index].index = right_index;
_open[this_index].index = this_index;
this_index = right_index;
}else{
break;
}
}
}
}
return obj_note;
}
运行结果如图
我们看到,耗时15毫秒,速度是这三个方法里最快的,但是因为这个数字是不够准确的,实际上,用二叉树查找法,会让A*算法的速度提高几倍到10几倍,在一些足够复杂的地图里,这个速度是成指数成长的。
4,总结
得出结论,用了A*算法,就要配套的用它的黄金搭档,二叉树,它可以让你的游戏由完美走向更完美。
[ 本帖最后由 lufy 于 2010-8-6 12:59 编辑 ]
作者:
司徒苍月 时间: 2010-7-14 12:14
直接说 寻路算法 更通俗些
作者:
lufy 时间: 2010-7-14 12:22
说的是,改
作者:
周瑜 时间: 2010-7-14 19:52
大致看了一下,这个A*算法其实就是Dijkstra算法,而最后的二叉树查找算法应该改名叫堆排序算法更准确一些。
作者:
tydea 时间: 2010-7-16 10:13
虽然不懂,但还是顶顶
作者:
将来的mod达人 时间: 2010-7-26 20:41
我想知道LZ的意图。。。。是想研究曹操传AI的行走路径= =?
作者:
陈珺 时间: 2010-8-3 00:05
A*是广度优先,做很多无用功,为了保证精确,把各种可能都比较过去,非常耗时
作者:
《苍狼白鹿传》 时间: 2010-8-5 17:13
假设从(0,0)到(40,40)有1600个单位,假设每单位有三个值 0 可移动 1不可移动 2已经移动过
首先可移动只有两个方向(算正方向,斜向算两步)
然后对四个方向编号,1上 2左 3下 4右,运动路径就被一串数字记录
当前坐标 2字节
先计算横纵坐标差值之和,就是走三角形两条直角边的距离
然后以这个距离作为最小值
横轴优先纵轴其次,先测试能否直接通过直角边到达
遇到障碍然后转变方向,只有两个选择 向上 向下
向上的话距离在增加,所以优先的还是向下,上一个单位优先测试向右(注意最开始不可能回头的)
比方达到(25,0)的时候,(26,0)是障碍
那么就尝试往(25,1)走遇到障碍尽量往目的地最近的点靠近
像这样的走直线在RPG中比较常见,然后遇到障碍物停住的现象也有
[ 本帖最后由 《苍狼白鹿传》 于 2010-8-5 17:19 编辑 ]
作者:
《苍狼白鹿传》 时间: 2010-8-5 17:24
当然被障碍物卡住只能说明AI太弱智
一般最优先的假设就是没有障碍
每一步都检测最靠近的走法
O A
A X 就想这样从(0,0)到(40,40)只有这两个方向是接近的,所以优先考虑着两个方向
O是假设弟N步所在 A是N+1步的CASE
内存存储空间比较多
第一步就有两个CASE 所以到障碍物之前就有2的N次方作为存储空间
但是 3 4 和 4 3是同样的结果,先下后右 先右后下
所以每一步方向记录的数字会对比, 那么34443和33444是一样的最后只统计每个数字的个数
如果到了死角
O A B
A B X
B X X B是障碍 A是预计的下一步,那么经过两个case以后返回结果是进入死角
这时候开始返回
返回也是先横坐标再纵坐标
不论向左还是向上都可以算远离了目标
所以在这种情况下马上继续按照最近原则找
考虑不回头原则
那么路径有可能是
A----
| X
| X
C-BX
| X
D
A-D
这样的测试是优先横坐标
比方从 0 0 到 5 5
有一排障碍
AOOOX
OOOXO
OOXOO
OXOOO
OOOOB
优先走到 3 0(准确的说还只是测试,不是真的走)
两个方向不能走,不能回头
然后在 2 0 拐弯
因为从 2 0 到 2 1 和到3 0 效果一样
但是优先横坐标
到了2 1 又被卡死 然后左走(最后1234四个方向相加减得出最近的结果)
这时候到了 1 1 ,优先考虑往最近方向 向下 到了1 2 于是根据这个原则,一直走到0 4然后又回到最初原则,横坐标
这样的话实际路程是11 而最近是8
这时候尝试缩减路程
最明显的是 A B
D C这样的路径直接变成 A
B
但是像
O O O
X X O
O O O
的路径可能难以发现
这时候就尝试变换横纵坐标走法
比方3 4 变成4 3
于是可以变成
O O X
X O O
O O O
这就缩短为
O O X
X O X
O O X
利用循环从开始到最后变换以后测试(前提是不撞上障碍)
实际上也有些路径计算就想这样 的,比方贴着墙走,然后走到了门口进去
[ 本帖最后由 《苍狼白鹿传》 于 2010-8-5 17:44 编辑 ]
作者:
墨叶 时间: 2010-8-5 17:49
疑问:对图1,最佳路线为下,右下,右上,上,上,上。总路程为72。
小于78。
作者:
《苍狼白鹿传》 时间: 2010-8-5 17:53
图挂了?不知道怎么回事都没看到
作者:
lufy 时间: 2010-8-6 13:04 标题: 回复 #10 墨叶 的帖子
看得真仔细阿,图是偷懒手动计算画出来的,一不小心画错了,改了一下,哈哈,非常感谢
作者:
northwind_x 时间: 2010-8-12 12:52
楼主图挂了……
作者:
lym20 时间: 2010-8-14 09:52
还是不懂
作者:
jakerl 时间: 2010-9-9 10:22
这是普通的Dynamic programming算法,会有curse of dimensionality
作者:
513633522 时间: 2010-12-3 11:08
路飞好厉害啊,高手,能否给个联系方式,向路飞学习下ActionScript 3.0
作者:
lufy 时间: 2010-12-3 11:26
原帖由 513633522 于 2010-12-3 11:08 发表
路飞好厉害啊,高手,能否给个联系方式,向路飞学习下ActionScript 3.0
我也不过是个初学者阿,高手可谈不上
一切都在学习中学习中......
欢迎光临 轩辕春秋文化论坛 (http://xycq.org.cn/forum/) |
Powered by Discuz! 5.0.0 |