经过我的优化后,速度比原来快了很多,但比起版主的还是慢.还要继续努力.不过终于是入AS3的门了.
var w:uint = 60;//地图横节点个数
var h:uint = 35;//地图纵节点个数
var r:uint = 10;//节点的长宽
var isEight:Boolean = true;//是否为八方向寻路
var time:uint;//记录时间
var field:MovieClip=new MovieClip();//地图
addChild(field);
var allNode:Array = new Array();//所有节点
var start_Piont:MovieClip;//寻路出发点
var end_Piont:MovieClip;//寻路目的地
var open_arr:Array;//开放列表
var block_arr:Array;//关闭列表
var path_arr:Array;//路径
var fail:Boolean = false;//是否找到路径
var isRun:Boolean = false;//是否正在寻路
init(field);
type_mc.addEventListener(MouseEvent.CLICK, typeHandler);
reset_mc.addEventListener(MouseEvent.CLICK, resetHandler);
//初始化地图
function init(field:MovieClip) {
for (var y:uint=0; y<h; y++) {
if (allNode[y]==undefined) {
allNode[y] = new Array();
}
for (var x:uint=0; x<w; x++) {
var everynode:MovieClip=new node();
allNode[y].push(field.addChildAt(everynode, field.numChildren));
allNode[y][x].px = x;
allNode[y][x].py = y;
allNode[y][x].x=x*r;
allNode[y][x].y=y*r;
//25%概率是不可通过,左上角一定为可通过
allNode[y][x].gotoAndStop(Math.random()>.25||(x==0&&y==0)?1:2);
//如果可以通过就添加点击事件
if (allNode[y][x].currentFrame == 1) {
allNode[y][x].addEventListener(MouseEvent.CLICK, setEndPiont);
}
}
}
field.x = 30;//Math.floor((stage.stageWidth-field.width)/2);
field.y = 10;//Math.floor((stage.stageHeight-field.height)/2)-10;
}
//节点被点击时之事件
function setEndPiont(e:MouseEvent):void {
if (!isRun) {
isRun = true;
//清除之前计算的节点
for (var y:uint=0; y<h; y++) {
for (var x:uint=0; x<w; x++) {
if (allNode[y][x].currentFrame>2) {
allNode[y][x].gotoAndStop(1);
}
}
}
//开始计时
time = getTimer();
open_arr = new Array();
block_arr = new Array();
path_arr = new Array();
//如果是第一次寻路,出发点是左上角,否则是上一次寻路的终点
start_Piont = end_Piont == null ? allNode[0][0] : end_Piont;
end_Piont = e.currentTarget;
//开始寻找
checkNeighbor(start_Piont);
}
}
//检测周围的节点
function checkNeighbor(node:MovieClip):void {
var thisNode:MovieClip = node;//当前正在检测的节点
var getEnd:Boolean = false;//是否找到目的地
//循环直到找到目的地
while (!getEnd) {
//将当前正在检测的节点存入关闭列表
block_arr.push(thisNode);
var checkList:Array = new Array();//当前节点的周围
//如果是八方向寻路,就加入四个角
if (isEight) {
if (thisNode.py>0 && thisNode.px>0) {
checkList.push(allNode[(thisNode.py-1)][(thisNode.px-1)]);
}
if (thisNode.py<h-1 && thisNode.px>0) {
checkList.push(allNode[(thisNode.py+1)][(thisNode.px-1)]);
}
if (thisNode.py>0 && thisNode.px<w-1) {
checkList.push(allNode[(thisNode.py-1)][(thisNode.px+1)]);
}
if (thisNode.py<h-1 && thisNode.px<w-1) {
checkList.push(allNode[(thisNode.py+1)][(thisNode.px+1)]);
}
}
if (thisNode.py>0) {
checkList.push(allNode[(thisNode.py-1)][(thisNode.px)]);
}
if (thisNode.px>0) {
checkList.push(allNode[(thisNode.py)][(thisNode.px-1)]);
}
if (thisNode.px<w-1) {
checkList.push(allNode[(thisNode.py)][(thisNode.px+1)]);
}
if (thisNode.py<h-1) {
checkList.push(allNode[(thisNode.py+1)][(thisNode.px)]);
}
//开始检测当前节点周围
var len:uint = checkList.length;
for (var i:uint = 0; i<len; i++) {
//周围的每一个节点
var neighboringNode:MovieClip = checkList[i];
//判断是否是目的地
if (neighboringNode == end_Piont) {
if (isEight) {
//如果是八方向寻路
if (neighboringNode.px != thisNode.px && neighboringNode.py != thisNode.py) {
//如果是角上的节点,需要再判断是否可以通行
if (allNode[(neighboringNode.py)][thisNode.px].currentFrame != 2 && allNode[(thisNode.py)][neighboringNode.px].currentFrame != 2) {
neighboringNode.nodeparent = thisNode;
getEnd = true;
break;
}
} else {
//如果不是角上的节点
neighboringNode.nodeparent = thisNode;
getEnd = true;
break;
}
} else {
//如果是四方向寻路,就直接得到目的地
neighboringNode.nodeparent = thisNode;
getEnd = true;
break;
}
}
//是否可通行
if (neighboringNode.currentFrame != 2) {
if (isEight) {
//八方向寻路,需要判断是否为角上的节点
if (neighboringNode.px != thisNode.px && neighboringNode.py != thisNode.py) {
//角上的节点需要判断是否可通过
if (allNode[(neighboringNode.py)][thisNode.px].currentFrame != 2 && allNode[(thisNode.py)][neighboringNode.px].currentFrame != 2) {
count(neighboringNode, thisNode);//计算该节点
}
} else {
count(neighboringNode, thisNode);//计算该节点
}
} else {
count(neighboringNode, thisNode);//计算该节点
}
}
}
if (!getEnd) {
//如果未找到目的地
if (open_arr.length>0) {
//开发列表不为空,找出F值最小的做为下一个循环的当前节点
thisNode = open_arr.splice(getMin(),1)[0];
} else {
//开发列表为空,寻路失败
fail = true;
break;
}
}
}
if (!fail) {
//如果寻路成功,开始画路径
drawPath(end_Piont);
//trace_mc.text = "可以到达!";
} else {
end_Piont = null;
trace_mc.text = "无法到达!";
fail = false;
isRun = false;
}
}
//计算邻节点
function count(neighboringNode:MovieClip, thisNode:MovieClip) {
//是否在关闭列表里
if (!isInArr(neighboringNode, block_arr)) {
//不在关闭列表里才开始判断
var newG:Number;
//判断是四方向还是八方向寻路,减化四方向寻路的计算
if (isEight) {
newG = neighboringNode.px == thisNode.px || neighboringNode.py == thisNode.py ? thisNode.G+10 : thisNode.G+14;
} else {
newG = thisNode.G+10;
}
if (isInArr(neighboringNode, open_arr)) {
//如果该节点已经在开放列表里
if (neighboringNode.G>=(newG)) {
//如果新G值小于或者等于旧值,则表明该路更优,更新其值
neighboringNode.G = newG;
getGHF(neighboringNode);
neighboringNode.nodeparent = thisNode;
}
} else {
//如果该节点未在开放列表里
//添加至列表
open_arr.push(neighboringNode);
neighboringNode.gotoAndStop(4);
//计算GHF值
neighboringNode.G = newG;
getGHF(neighboringNode);
neighboringNode.nodeparent = thisNode;
}
}
}
//判断某值是否存在于数组中
function isInArr(obj, arr:Array):Boolean {
var len:uint = arr.length;
for (var i:Number = 0; i<len; i++) {
if (obj == arr[i]) {
return true;
}
}
return false;
}
//生成GHF值
function getGHF(obj:MovieClip):void {
if (!obj.G) {
obj.G = 0;
}
obj.H = 10*(Math.abs(obj.px-end_Piont.px)+Math.abs(obj.py-end_Piont.py));
obj.F = obj.G+obj.H;
}
//得到开放列表里拥有最小F值的节点在列表里的位置
function getMin():uint {
var len:uint = open_arr.length;
var min:Object = new Object();
min.F = 100000;
min.i = 0;
for (var i:uint = 0; i<len; i++) {
if (min.F>open_arr[i].F) {
min.F = open_arr[i].F;
min.i = i;
}
}
return min.i;
}
//画路径
function drawPath(node:MovieClip):void {
var pathNode:MovieClip = node;
//倒过来得到路径
while (pathNode != start_Piont) {
path_arr.push(pathNode);
pathNode = pathNode.nodeparent;
}
path_arr.push(pathNode);
//开始画
var len:uint = path_arr.length;
for (var i:Number = 0; i<len; i++) {
path_arr[i].gotoAndStop(3);
}
//显示计算时间
trace_mc.text = "耗时:"+(getTimer()-time)+" 毫秒,路长:"+path_arr.length+" .";
isRun = false;
}
//四方向八方向节换按钮的点击事件
function typeHandler(e:Event):void {
isEight = !isEight;
if (isEight) {
e.currentTarget.label = "改为四方向";
} else {
e.currentTarget.label = "改为八方向";
}
}
//重置按钮的点击事件
function resetHandler(e:Event):void {
start_Piont = allNode[0][0];
end_Piont = null;
for (var y:uint=0; y<h; y++) {
for (var x:uint=0; x<w; x++) {
allNode[y][x].gotoAndStop(Math.random()>.25||(x==0&&y==0)?1:2);
if (allNode[y][x].currentFrame == 1) {
allNode[y][x].addEventListener(MouseEvent.CLICK, setEndPiont);
} else {
allNode[y][x].removeEventListener(MouseEvent.CLICK, setEndPiont);
}
}
}
}
A星as3.swf:
源文件:
A星as3.rar