战旗游戏简单寻路的例子续

直接上代码,里面的注释很详细,只是简单的实现了
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>走动步数</title>
</head>
<body >
<canvas  id="canvas" style="border:1px solid #d3d3d3;">
    你的浏览器不支持h5
</canvas>
<script>
    /**
     * 构思:首先,用深搜便利出行动力所能达到的所有点 ,在显示出来
     *
     */

    //人物的初始坐标 和  人物的行动力
    var menx = 10,meny = 10,stap = 6;

    //大地图的长款
    var n = 50,m = 50;

    //人物行走时的坐标
    var el={x:0,y:0};

    //所有行走路线的数组
    var xingZouluxian= [];

     function $(id){
        return document.getElementById(id);
    }

    var canvas  = $("canvas");
    var ctx = canvas.getContext("2d");
    canvas.width = 500;//画布的宽
    canvas.height = 500;//画布的高

    ctx.fillRect(menx*10,meny*10,10,10);//实心小方块 人物显示的地方
    canvas.addEventListener("click",function(e){
        var  x = e.offsetX;
        var  y = e.offsetY;
        el.x = Math.floor(x/10);
        el.y = Math.floor(y/10);
        //通过搜索  计算人物在行动力范围类  可以到达的地方
        dfs(menx,meny,stap);

        canvas.height = canvas.height;//重绘画布

        a[menx][meny] = 1;//人物坐标给初始化为0,避免下面重绘给覆盖掉
        if(x>menx*10&&x<menx*10+10&&y>meny*10&&y<meny*10+10){//判断点击的是否在人物身体范围

           ctx.save();//记住画布状态
           ctx.fillStyle = "#4A4AFF";//颜色
            //绘制行动路线

           for(var i =0;i< a.length;i++){
                    for(var j =0;j<a[i].length;j++){
                        if(a[i][j]==1){
                            ctx.fillRect(i*10,j*10,10,10);
                        }
                    }
                }

            ctx.restore();//回到画布上一个状态
            ctx.fillRect(menx*10,meny*10,10,10);//绘制人物 当前位置
        }else{
            if(que(x,y)){//如果点击超过行动界限  取消这次的行动并清除掉行动图

                canvas.height = canvas.height;//重绘画布
                ctx.fillRect(menx*10,meny*10,10,10);//重画人物
            }else{//如果没超出行动力范围 且没点击人物
                canvas.height = canvas.height;
                ctx.fillRect(menx*10,meny*10,10,10);
                //计算路线
                bfs();
                //最短路线数组
                var luxian = [];
                //初始化fq 让他等于xingZouluxian数组的最后一条序号
                var fq = tail-1;
                litui(xingZouluxian);
                function litui(xingZouluxian){
                    //用于接受的临时数组  方便放入luxian的二位数组中
                    var sss = [];
                    //从最后一点开始取坐标
                    sss.push(xingZouluxian[fq].x) ;
                    sss.push(xingZouluxian[fq].y);
                    luxian.push(sss);
                    // f存的是这一条的父路径序号
                    fq  =  xingZouluxian[fq].f;
                    //放在返回上面  否则fq等于0 后没有父路径会报错
                    if(fq==0){
                        return luxian;
                    }
                    //必须返回整个数组
                    return litui(xingZouluxian);
                }
                //给蛇头预定的值
                if(luxian.length>0){
                    var num = luxian.length-index;
                    menx = luxian[num][0];
                    meny = luxian[num][1];
                }

                ctx.save();//记住画布状态
                ctx.fillStyle = "red";//颜色
                //绘制行动路线

                console.log(luxian);
                luxian = luxian.reverse();
                for(var i =0;i< luxian.length;i++){
                    ctx.fillRect(luxian[i][0]*10,luxian[i][1]*10,10,10);
                }

                ctx.restore();//回到画布上一个状态
                //动态的画人物的行走
                runRenwu(luxian);
            }
        }

    })

    //记录  初始化记录数组
    var  book = [];
    for(var i =0;i<m;i++){
        var now = [];
        for(var j = 0;j<n;j++){
            now[j] = 0;
        }
        book[i] = now;
    }
    //地图 记录行动力所能达到的点
    var a = [];

    for(var i =0;i<n;i++){
        var now1 = [];
        for(var j = 0;j<n;j++){
            now1[j] = 0;
        }
        a[i] = now1;
    }


    //这是计算行动力所能达到的点的坐标 深搜
     function dfs(x,y,num){//参数分别为开始位置的x,y  和 行动力
         //方向
         var next = [
                 [0,1],//右
                 [1,0],//下
                 [0,-1],//左
                 [-1,0]//上
         ]
         var tx,ty;//下一步可以去的点
         if(num==0){
           return;
         }
         for(var k =0;k<=3;k++){
             tx = x + next[k][0];
             ty = y + next[k][1];
             if(tx<0||tx>=50||ty<0||ty>=50){
                 continue;//直接跳过本次循环 (brack是跳过整个循环)
             }
             if(book[tx][ty]==0){
                 book[tx][ty]=1;//记录这个点已经走过
                 num--;//走过后行动力就减一(不同地形可以减不同的行动力)
                 a[tx][ty] = 1;//这个点可以到达那么让其值等于1
                 dfs(tx,ty,num);//在检测这个点相邻可以走的点
                 book[tx][ty]=0;//下一个点不能走后返回到这一步,去掉标记,让这个点可以走
                 num++;//既然退回了一步,那么行动力就还回去(减多少还多少)
             }
         }

         return;//如果这个点不能走了,就返回到上一个能走的点尝试(剩下的能走的点是否可以行动)
     }

    //这里是计算路线的方法   广搜
     function bfs(){
        //构建地图
        //自定义类
        function note(x,y,s,f){
            this.x = x;//横坐标
            this.y = y;//纵坐标
            this.s = s;//步数
            this.f = f;//父亲在队列中的编号
        }
        //用来存储地图
        var a = [];
        for(var i =1;i<=n;i++){
            var now = [];
            for(var j =1;j<=m;j++){
                now[j] = 0;
            }
            a[i] = now;
        }
        //记录是否走过的队列
        var book_2 = [];
        for(var i =1;i<=n;i++){
            var now = [];
            for(var j =1;j<=m;j++){
                now[j] = 0;
            }
            book_2[i] = now;
        }
        //定义一个用于表示走的方向的数组
        var next = [[0,1],[1,0],[0,-1],[-1,0]];//右 下 左 上




        //迷宫开始地点
        startx = menx;
        starty = meny;
        index = 1;

        //终点
        p = el.x;
        q = el.y;

        //队列初始化
        head = 1;
        tail = 1;
         xingZouluxian[tail] = new note(startx,starty,0,0);
        tail++;
        //打印所有走过的点
        //console.log(xingZouluxian);
        //打印迷宫

         book_2[startx][starty] = 0;


        flag = 0;//用来标记是否到达终点,0表示暂时没到达,1表示到达
        //当前队列不为空时循环
        while(head<tail){
            //枚举四个方向
            for(k =0 ;k<=3;k++){
                //计算下一个点的坐标
                tx = xingZouluxian[head].x + next[k][0];
                ty = xingZouluxian[head].y + next[k][1];
                //判断是否越界
                if(tx<1||tx>n||ty<1||ty>m){
                    continue;
                }
                //判断是否是障碍物或者已经在路径中
                if(a[tx][ty]==0&&book_2[tx][ty]==0){
                    //把这个点标记为已经走过
                    //注意宽搜只入队一次,所以和深搜不同,不需要将book_2数组还原
                    book_2[tx][ty] =1;
                    //插入新的点到队列中
                    xingZouluxian[tail] = new note(tx,ty,xingZouluxian[head].s+1,head);//因为这个点是从head扩展来的,所以他的父节点
                    //是head,f代表路径   s代表步数是父节点的步数加1
                    tail++;
                }
                //如果到目标点了,停止扩展,任务结束,退出循环
                if(tx==p&&ty==q){
                    //注意下面的两句话位置不要写反了
                    flag = 1;
                    break;
                }

            }
            if(flag==1){
                break;
            }
            head++;//注意这个地方千万不要忘记,当一个或站点结束后,head++才能对后面的点在进行扩展

        }


        return xingZouluxian;



    }

    function que(x,y){//判断点击处是否在行动范围内

        for(var i =0;i< a.length;i++){
            for(var j =0;j<a[i].length;j++){
                if(a[i][j]==1){
                    if(x>i*10&&x<i*10+10&&y>j*10&&y<j*10+10){
                        return false;
                    }
                }
            }
        }
        return true;
    }

    function runRenwu(a){
        var luxian = a.concat();
        setTimeout(function(){
            canvas.height = canvas.height;
            ctx.save();//记住画布状态
            ctx.fillStyle = "red";//颜色
            //绘制行动路线



            var nextLuxian = luxian.shift();
            console.log(nextLuxian);

            for(var i =0;i< luxian.length;i++){
                ctx.fillRect(luxian[i][0]*10,luxian[i][1]*10,10,10);
            }

            ctx.restore();//回到画布上一个状态
            if(luxian.length==0){//行动完毕

                menx =nextLuxian[0];
                meny =nextLuxian[1];
                ctx.fillRect(nextLuxian[0]*10,nextLuxian[1]*10,10,10);
                console.log(menx+','+meny);
                aClear();
                return;
            }
            ctx.fillRect(nextLuxian[0]*10,nextLuxian[1]*10,10,10);
            runRenwu(luxian);
        },200)


    }

    function  aClear(){//清除记录可到达范围数组a
        for(var i=0;i< a.length;i++){
            for(var j = 0;j< a.length;j++){
                a[i][j]=0;
            }
        }
    }
</script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值