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

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

<!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>
<think>嗯,用户问的是“SLG大地图怎么做”,首先我需要明确SLG指的是什么。SLG通常指策略类游戏,比如《文明》系列或者《火焰纹章》。这类游戏的大地图设计是关键,所以用户可能是一个游戏开发者或者独立制作人,想要了解如何构建一个适合策略游戏的大地图。 首先,我应该分解大地图设计的核心要素。可能需要考虑地图类型,比如六边形格还是方形格,地形设计,资源分布,势力划分,移动规则等等。然后需要思考技术实现,比如使用什么引擎,地图生成算法,数据存储方式,还有如何优化性能,因为大地图可能很大,需要分块加载或者LOD技术。 用户可能已经有基本概念,但需要具体的步骤和注意事项。可能还需要美术和程序之间的协作,比如如何将设计转化为实际可玩的游戏地图。此外,随机生成与固定地图的优缺点也是需要考虑的,比如《文明》是随机生成,而某些战棋游戏使用固定地图。 需要确保回答结构清晰,分步骤说明,同时涵盖设计和技术实现两个方面。还要注意用户可能对专业术语不太熟悉,所以解释时要尽量通俗,但保持准确性。比如解释A*算法时,可以简单说明是路径寻找的常用方法,而不深入细节。 另外,用户可能关心如何平衡游戏性,比如资源分布是否均匀,地形对策略的影响,以及如何测试地图的合理性。这部分需要给出实际例子或方法,比如使用自动化测试或者玩家反馈。 最后,总结关键点,确保用户有一个全面的理解,并能根据指导开始实践。可能还需要推荐一些工具或资源,比如Unity的Tilemap,或者Perlin噪声算法的应用,帮助用户进一步研究。</think>好的,我将从设计思路和技术实现两个层面,分步骤解释如何制作SLG(策略类游戏)的大地图: 一、核心设计要素 1. 地图结构类型 - 六边形网格(Hex Grid):$$移动方向=6$$ 适合战略深度(如《文明》系列) - 方形网格(Square Grid):$$移动方向=4/8$$ 更易实现(如早期《火焰纹章》) - 无缝大地图:需配合LOD(Level of Detail)技术$$ \text{渲染精度} \propto \frac{1}{\text{观察距离}} $$ 2. 地形系统设计 ```伪代码 class Terrain { 属性: - 移动消耗值: int - 防御加成: float - 资源产出: Dict<ResourceType, float> 方法: - 生成视觉效果() } ``` 3. 动态元素设计 - 战争迷雾:$$Fog(x,y) = \begin{cases} 1 & \text{未探索} \\ 0 & \text{已探索} \end{cases}$$ - 动态天气系统:需考虑路径损耗修正$$移动成本' = 移动成本 \times (1 + 天气修正系数)$$ 二、技术实现流程 1. 数据存储方案 ```typescript // 使用稀疏矩阵存储(适合大型地图) interface MapData { chunkSize: 32, // 分块尺寸 chunks: Map<string, Terrain[][]> // 坐标分块存储 } ``` 2. 关键算法实现 - 路径搜索:改进A*算法$$f(n) = g(n) + h(n) + \lambda \cdot \text{地形威胁值}$$ - 地图生成:Perlin噪声+控制点 $$Height(x,y) = \sum_{i=1}^{n} \frac{Noise(2^i x, 2^i y)}{2^i}$$ 3. 性能优化方案 - 视锥体裁剪:$$ \text{渲染范围} = \lceil \frac{\text{屏幕对角线}}{2 \times \text{格子尺寸}} \rceil + 2 $$ - 异步加载:使用Job System实现后台地图数据加载 三、平衡性设计要点 1. 资源分布公式 $$资源密度 = \frac{\text{基础值}}{1 + e^{-k(战略价值等级-5)}}$$ 确保高价值区域竞争激烈 2. 移动规则设计 | 地形类型 | 移动消耗 | 视野修正 | 战斗加成 | |----------|---------|---------|---------| | 平原 | 1 | +0 | 0% | | 森林 | 2 | -30% | +20% | | 山脉 | 3 | +50% | +40% | 四、实施建议 1. 使用现成引擎工具: - Unity:Tilemap+NavMesh - Unreal:Landscape+AI Navigation 2. 开发迭代流程: 原型阶段 → 白盒测试(纯数据验证)→ 美术资源替换 → 多分辨率适配 3. 测试重点: - 路径搜索效率:确保在$10^6$格量级下寻路时间 < 200ms - 内存管理:单区块内存占用应 < 16MB - 战争迷雾同步:多人游戏中延迟补偿机制 建议先使用Tiled Map Editor等工具制作小型原型(如100x100网格),验证核心机制后再扩展。大型SLG地图开发周期通常需要6-12个月,需注重模块化设计和数据驱动架构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值