基于四方向A星寻路延展的连连看

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的限制后可能连线失败

效果图:



猜你喜欢

转载自blog.csdn.net/qq_39194398/article/details/80900537