import flash.geom.Point;
import flash.display.Sprite;
import com.qrpg.Algorithm.PathFinding;
var t:int;
var field:Sprite = new Sprite();//地图图层
addChild(field);
var linePath:Sprite = new Sprite();//网格图层
addChild(linePath);
var allNode:Array = []; //节点数据(小格子)
var map:Array = []; //网格
//随机制定网格,35行60列
for (var mapy:int=0; mapy<35; mapy++) {
if (map[mapy]==undefined) {
map[mapy] = [];
}
//随机生成网格
for (var mapx:int=0; mapx<60; mapx++) {
map[mapy][mapx] = Math.random()>.25 ? 0 : 1 ;
}
}
//var map:Array=[[0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0],[0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0],[0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,1],[0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0],[1,1,0,0,0,1,1,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0],[0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0],[0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0],[1,1,0,0,0,0,1,0,0,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,1,1,0,1,0,1,1,0,0,1,1,0,0,0,0],[0,1,0,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,1,0,1,0,0],[1,1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,1,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0],[0,1,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0],[1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1],[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0],[1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,1,0,0,0,1,0],[0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0],[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1],[0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0],[0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0],[0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,1],[0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0],[0,0,1,0,1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1],[0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,1,1,0,1,1,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0],[0,0,0,0,1,0,0,0,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0],[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,1],[0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0],[1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,1,0,1,0,0,1,1,0],[0,0,0,1,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0]];
var w:int = map[0].length; //列长度
var h:int = map.length; //行长度
var path:Array; //路径1
var path2:Array; //路径2
var startpoint:Point = new Point(); //程序启动时的始点
var findPath:PathFinding = new PathFinding(map); //创建包含网格地图的数组(元素是对象)
//在界面上画出节点
for (var py:int=0; py<h; py++) {
if (allNode[py]==undefined) {
allNode[py] = [];
}
for (var px:int=0; px<w; px++) {
allNode[py].push(field.addChildAt(new node(), field.numChildren)); //把新建的节点加入到每一行中,列不断增加
allNode[py][px].p = new Point(px, py); //用数据索引新建一个当前点的代表坐标点
allNode[py][px].x=px*10; //设定此节点的坐标
allNode[py][px].y=py*10;
//allNode[py][px].gotoAndStop(map[py][px]==0?1:2); //原理和下面相同
if (map[py][px]==0) { //判断是否不是障碍
allNode[py][px].stop(); //如果不是障碍,则停止增加节点,增加事件监听
allNode[py][px].addEventListener(MouseEvent.CLICK, findHandler);
} else {
allNode[py][px].gotoAndStop(2);//障碍进入第二帧
}
}
}
field.x = 30; //设定图层开始显示的坐标
field.y = 10;
linePath.x = field.x+5; //第一个节点的中心点
linePath.y = field.y+5;
function findHandler(e:MouseEvent):void {
t = getTimer(); //取得当前的毫秒数
for (var y:int=0; y<h; y++) {
for (var x:int=0; x<w; x++) {
if (allNode[y][x].currentFrame>2) { //不允许 每个节点的帧数大于2
allNode[y][x].gotoAndStop(1);
}
}
}
//指定默认的起始点和当前点击的节点的对应P点(*10可得到准确左上角路径),返回一个数组
path = findPath.path4(startpoint, e.currentTarget.p);
var len:int = path.length;
//把路径的格子设为绿色
for (var i:int=0; i<len; i++) {
allNode[path[i].y][path[i].x].gotoAndStop(3);
}
if (len==0) {
trace_mc.text = "无法到达!"; //如果返回路径的长度为0,则表示路径为0 ,不能到达
} else {
//path2 = findPath.optimizePath();
path2=path;
//画出路径上的白色线条
var len2:int = path2.length;
linePath.graphics.clear();
linePath.graphics.lineStyle(2,0xffffff,1);
for (var j:int=0; j<len2; j++) {
if (j==0) {
linePath.graphics.moveTo(path2[j].x*10, path2[j].y*10);
} else {
linePath.graphics.lineTo(path2[j].x*10, path2[j].y*10);
}
}
startpoint = e.currentTarget.p;
trace_mc.text = "经过格子"+len+"个,";
}
//计算寻路用了多少时间
trace_mc.appendText("所用时间:"+(getTimer()-t)+"毫秒。");
}
reset_mc.addEventListener(MouseEvent.CLICK, resetHandler);
function resetHandler(e:MouseEvent):void {
}
//
package com.qrpg.Algorithm{
import flash.geom.Point;
import com.qrpg.Algorithm.Diagonal;
public class PathFinding {
private var _map:Array;//网格地图(元素是对象)
private var _w:int;//网格地图的宽
private var _h:int;//网格地图的高
private var _open:Array;//开放列表
private var _starPoint:Object;
private var _endPoint:Object;
public var path:Array = [];//计算出的路径
public function PathFinding(map:Array) {
_map = []; //接收网格地图
_w = map[0].length;
_h = map.length;
for (var y:int=0; y<_h; y++) {
if (_map[y]==undefined) {
_map[y] = [];
}
//把每个节点创建成对象,再保存到数组里面
for (var x:int=0; x<_w; x++) {
_map[y][x] = {x:x, y:y, value:map[y][x], block:false, open:false, value_g:0, value_h:0, value_f:0, nodeparent:null};
}
}
}
//四方向寻路
public function path4(star:Point, end:Point):Array {
path = [];
_starPoint = _map[star.y][star.x]; //取得起始点和结束点
_endPoint = _map[end.y][end.x];
var __getEnd:Boolean = false; //判断是否到了结束点
initBlock(); //寻路前的初始化
var __thisNode:Object = _starPoint; //得到开始点
//循环判断是否到了结束点,直到以最优路径方式找到结束点为止
while (!__getEnd) {
__thisNode.block = true; //把起始点设为障碍
var __checkList:Array = []; //检查数组
//把当前的周围的四个节点加入检查数组中,等待检查
if (__thisNode.y>0) {
__checkList.push(_map[(__thisNode.y-1)][__thisNode.x]);
}
if (__thisNode.x>0) {
__checkList.push(_map[__thisNode.y][(__thisNode.x-1)]);
}
if (__thisNode.x<_w-1) {
__checkList.push(_map[__thisNode.y][(__thisNode.x+1)]);
}
if (__thisNode.y<_h-1) {
__checkList.push(_map[(__thisNode.y+1)][__thisNode.x]);
}
//开始检测当前节点周围
var __len:int = __checkList.length;
for (var i:int = 0; i<__len; i++) {
//取得周围的每一个节点
var __neighboringNode:Object = __checkList[i];
//判断是否是目的地
if (__neighboringNode == _endPoint) {
__neighboringNode.nodeparent = __thisNode; //设定此周围节点的父节点,即连接此的节点的上一节点
__getEnd = true;
break;
}
//是否可通行
if (__neighboringNode.value == 0) {
count(__neighboringNode, __thisNode);//计算该节点,传送周围节点和当前中间点过去
}
}
if (!__getEnd) {
//如果未找到目的地
if (_open.length>0) {
//开发列表不为空,找出F值最小的做为下一个循环的当前节点
__thisNode = _open.splice(getMin(),1)[0];
} else {
//开发列表为空,寻路失败
return [];
}
}
}
drawPath();
return path;
}
//优化路径
public function optimizePath():Array {
var __len:int = path.length;
var __path:Array = [];
var diagonal:Array = []; //斜线数组
var __dLen:int;
var __cross:Boolean = true;
var __currentNode:Point = path[0]; //起点
__path.push(path[0]); //加入到优化后的数组
for (var i:int=1; i<__len; i++) {
diagonal = Diagonal.each(__currentNode, path[i]);
__dLen = diagonal.length; //返回一个数组
__cross = true;
for (var j:int=0; j<__dLen; j++) {
if (_map[diagonal[j].y][diagonal[j].x].value == 1) {
__cross = false;
break;
}
}
if (!__cross) {
if (i>1) {
__currentNode = path[(i-1)];
__path.push(path[(i-1)]);
}
}
}
__path.push(path[(__len-1)]);
return __path;
}
//寻路前的初始化,设置每个节点的节点属性
private function initBlock():void {
for (var y:int=0; y<_h; y++) {
for (var x:int=0; x<_w; x++) {
_map[y][x].open = false; //可以通过
_map[y][x].block = false; //障碍
_map[y][x].value_g = 0;
_map[y][x].value_h = 0;
_map[y][x].value_f = 0;
_map[y][x].nodeparent = null; //寻路过程中的上一点
}
}
_open = [];
}
//计算每个节点,接收周围节点和周围节点的中间点
private function count(neighboringNode:Object, centerNode:Object):void {
//是否在关闭列表里
if (!neighboringNode.block) {
//不在关闭列表里才开始判断
var __g:Number= centerNode.value_g+10;
//判断此点是否是障碍
if (neighboringNode.open) {
//如果该节点已经在开放列表里
if (neighboringNode.value_g>=__g) {
//如果新G值小于或者等于旧值,则表明该路更优,更新其值
neighboringNode.value_g = __g;
ghf(neighboringNode); //计算GHF的值
neighboringNode.nodeparent = centerNode; //把周围节点的上一节点设为中心节点
}
} else {
//如果该节点未在开放列表里
//添加至列表
addToOpen(neighboringNode);
//计算GHF值
neighboringNode.value_g = __g;
ghf(neighboringNode);
neighboringNode.nodeparent = centerNode;
}
}
}
//画路径
private function drawPath():void {
var __pathNode:Object = _endPoint;
//倒过来得到路径
while (__pathNode != _starPoint) {
path.unshift(new Point(__pathNode.x, __pathNode.y));
__pathNode = __pathNode.nodeparent;
}
path.unshift(new Point(__pathNode.x, __pathNode.y));
}
//加入开放列表
private function addToOpen(newNode:Object):void {
_open.push(newNode);
newNode.open = true;
}
//计算周围节点的ghf各值
private function ghf(node:Object):void {
var __dx:Number = Math.abs(node.x-_endPoint.x);
var __dy:Number = Math.abs(node.y-_endPoint.y);
node.value_h = 10*(__dx+__dy); //计算周围节点到结束点的X,Y的相差距离(X相差距离+Y相差距离)
node.value_f = node.value_g+node.value_h; //计算最优路径+XY的相差距离 (总距离)
}
//得到开放列表里拥有最小F值的节点在列表里的位置
private function getMin():int {
var __len:int = _open.length;
var __f:Number = 100000;
var __i:int = 0;
for (var i:int = 0; i<__len; i++) {
if (__f>_open[i].value_f) {
__f = _open[i].value_f;
__i = i;
}
}
return __i;
}
}
}