module ui {
export interface BlockData {
x: number,/**横向第几位 */
y: number,/**竖向第几位 */
tag: number,/**能否通过,0可以,1不行 */
}
export interface TagData {
tag: number,
index: number
}
export enum Direction {
up = 1,
down = 2,
left = 3,
right = 4
}
export class AStarUI extends eui.Component implements network.IMessage {
private blockGroup: eui.Group;
private line_group: eui.Group;
private btnReset: eui.Button;
private mask_rect: eui.Rect;
public static startBlock: ui.Block = null;
public static endBlock: ui.Block = null;
private blockMap: { [ind: number]: ui.Block } = {};
private openList: ui.Block[] = [];
private closeList: ui.Block[] = [];
constructor() {
super();
this.addEventListener(eui.UIEvent.COMPLETE, this.uiComplete, this);
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.addToStage, this);
this.skinName = "resource/ui/aStarWin.exml";
}
private uiComplete(): void {
this.mask_rect.visible = false;
this.blockGroup.removeChildren();
let x1 = 1,
y1 = 1;
let tagArr = this.getTagArr();
for (let i = 0; i < 100; i++) {/**设置一10x10地图块 */
let data: ui.BlockData = { x: x1, y: y1, tag: tagArr[i].tag };
let block: ui.Block = new ui.Block(data);
this.blockGroup.addChild(block);
this.blockMap[x1 + "" + y1] = block;/**块对应键存入 */
x1++;
if (x1 == 11) {
x1 = 1;
y1++;
}
}
}
private onBtnReset(): void {
this.uiComplete();
}
private addToStage(): void {
network.Message.getIns().add(network.Msg.START_CHECK, this);
this.btnReset.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onBtnReset, this);
}
resMsg(code: number, data: any) {
if (code == network.Msg.START_CHECK) {
this.findWay();
}
}
private findWay(): void {
this.mask_rect.visible = true;
this.openList = [];
this.closeList = [];
let beginBlock: ui.Block = AStarUI.startBlock;
this.searchBlock(beginBlock);
}
private searchBlock(beginBlock: ui.Block): void {/**解释参照 http://blog.csdn.net/agroupofruffian/article/details/77700338 */
/**寻找当前起点块上下左右四个块 */
let blockArr: ui.Block[] = [];
let upBlock = this.findBlock(Direction.up, beginBlock);
if (upBlock) {
blockArr.push(upBlock);
}
let downBlock = this.findBlock(Direction.down, beginBlock);
if (downBlock) {
blockArr.push(downBlock);
}
let leftBlock = this.findBlock(Direction.left, beginBlock);
if (leftBlock) {
blockArr.push(leftBlock);
}
let rightBlock = this.findBlock(Direction.right, beginBlock);
if (rightBlock) {
blockArr.push(rightBlock);
}
/**新块数组的前一个块设置为当前起点块 */
blockArr.forEach(block => {
block.lastBlcok = beginBlock;
});
/**新块里有终点块,即为找到,结束 */
if (blockArr.indexOf(AStarUI.endBlock) != -1) {
this.showWay();
return;
}
/**新块数组追加到开放数组 */
this.openList = this.openList.concat(blockArr);
/**当前起点块已检查数组中,加入已检查数组 */
if (this.closeList.indexOf(beginBlock) == -1) {
this.closeList.push(beginBlock)
}
let that = this;
/**开放数组排序,F = G + H,g为最初起点到当前块的步数,H为当前块到终点的步数(定值) */
this.openList.sort((a, b) => {
let a_last = a.lastBlcok,
b_last = b.lastBlcok;
let Ga = that.getGValue(a_last),
Gb = that.getGValue(b_last);
let Ha = Math.abs(a.data.x - AStarUI.endBlock.data.x) + Math.abs(a.data.y - AStarUI.endBlock.data.y),
Hb = Math.abs(b.data.x - AStarUI.endBlock.data.x) + Math.abs(b.data.y - AStarUI.endBlock.data.y);
return (Ga + Ha - Gb - Hb);
});
/**开放列表中选取F最小(即步数最少)块作为新起点 */
let bestBlock = this.openList.shift();
/**新起点不存在,即未寻得路,结束 */
if (!bestBlock) {
this.wrongWay();
return;
}
/**新起点做参数继续寻找 */
this.searchBlock(bestBlock);
}
private findBlock(dir: Direction, curBlock: ui.Block): ui.Block {
let newInd: string = "";
if (dir == Direction.up) {
newInd = (curBlock.data.x) + "" + (curBlock.data.y - 1);
} else if (dir == Direction.down) {
newInd = (curBlock.data.x) + "" + (curBlock.data.y + 1);
} else if (dir == Direction.left) {
newInd = (curBlock.data.x - 1) + "" + (curBlock.data.y);
} else if (dir == Direction.right) {
newInd = (curBlock.data.x + 1) + "" + (curBlock.data.y);
}
let block: ui.Block = this.blockMap[newInd];
if (block == AStarUI.endBlock) {
return block;
}
if (block && (block.data.tag == -1) && this.closeList.indexOf(block) == -1) {/**寻得的新块存在且不在已检查数组中,障碍块条件补充 */
if (this.openList.indexOf(block) != -1) {/**新块在开放数组中 */
let oldGa = 0, newGa = 0;
let bl = block.lastBlcok;
oldGa = this.getGValue(block.lastBlcok);/**最初起点到当前新块步数 */
newGa = this.getGValue(curBlock);/**最初起点块到参数块再到当前新块的步数 */
if (oldGa > newGa) {/**步数少的,设置为新块的前一块 */
block.lastBlcok = curBlock;
}
return null;
} else {
return block;
}
} else {
return null;
}
}
private getGValue(block: ui.Block): number {
let value = 0;
while (block) {
value++;
block = block.lastBlcok;
}
return value;
}
/**显示路线 */
private showWay(): void {
//先划线再置空
util.SoundManager.getIns().playSound(util.SoundType.line1);
let pointArr: egret.Point[] = [];
let block: ui.Block = AStarUI.endBlock;
while (block != null) {
let point: egret.Point = block.localToGlobal();
point.x += 30;
point.y += 30;
pointArr.push(point);
block = block.lastBlcok;
}
let beginPoint: egret.Point = pointArr.shift();
let shape: egret.Shape = new egret.Shape;
this.line_group.addChild(shape);
shape.graphics.lineStyle(2, 0x133F07);
shape.graphics.moveTo(beginPoint.x, beginPoint.y);
while (pointArr.length != 0) {
let point: egret.Point = pointArr.shift();
shape.graphics.lineTo(point.x, point.y);
}
shape.graphics.endFill();
egret.setTimeout(this.endSearch, this, 60);
}
private endSearch(): void {
this.line_group.removeChildren();
AStarUI.startBlock.showAni();
AStarUI.startBlock = null;
AStarUI.endBlock.showAni();
AStarUI.endBlock = null;
this.mask_rect.visible = false;
}
/** 路线未寻得*/
private wrongWay(): void {
AStarUI.startBlock.setTagStatus();
AStarUI.startBlock = null;
AStarUI.endBlock.setTagStatus();
AStarUI.endBlock = null;
this.mask_rect.visible = false;
}
/** */
private getTagArr(): TagData[] {
let arr: TagData[] = [];
while (arr.length != 100) {
let tag: number = Math.ceil(Math.random() * 100) % 16;
arr.push({ tag: tag, index: Math.ceil(Math.random() * 100) });
arr.push({ tag: tag, index: Math.ceil(Math.random() * 100) });
}
arr.sort((a, b) => {
return a.index - b.index;
})
return arr;
}
}
}
局限:
1、未判断二次拐弯限制;
2、由于是基于A星寻路,所以加1的限制后可能连线失败
效果图: