地图之战争迷雾/地图算法/自动导航(一)
战争迷雾
TiledMap 创建黑色覆盖块,然后使用碰撞组件,控制黑色块的显示和隐藏
地图算法
在有些游戏中,地图需要随机生成,比如游戏中的迷宫等,这就需要地图生成的算法;在角色扮演类游戏中,角色需要在地图中找到一条合适的路径,这就需要寻路算法,最常用的寻路算法就是A星路径搜索算法
Roguelike算法(地图生成)
Roguelike是角色扮演游戏(RPG)的一个子类(Roguelike-RPG),其原型——《Rogue》是20世纪80年代初,由Michael Toy和Glenn Wichman两位软件工程师共同在UNIX系统上开发,并在大型机上运行的游戏,Roguelike是角色扮演游戏(RPG)的一个子类(Roguelike-RPG),其原型——《Rogue》是20世纪80年代初,由Michael Toy和Glenn Wichman两位软件工程师共同在UNIX系统上开发,并在大型机上运行的游戏,在2008年的国际Roguelike发展会议上Roguelike游戏有了明确的定义,它的特点包括:
1)生成随机性。每一次新开局游戏都会随机生成游戏场景、敌人、宝物等不同事物。这样玩家的每一次冒险历程也都将是独一无二,不可复制的。
2)进程单向性。存档功能的唯一作用就是记录你当前的游戏进度,每当存档被读取时,对应的进度就会被清空,直到你进行下一次存档。
3)不可挽回性。在大多数Roguelike游戏中,每一个角色只有一次生命,一个角色的死亡意味着玩家将永远失去该角色。无论你是主角、敌人、物品还是场景。在很多玩家眼中,这正是Roguelike的乐趣所在。
4)游戏非线性。严谨而不失灵活性的游戏规则,使游戏具备了很高的自由度,在这类游戏中,玩家可以发挥想象力,利用各种方法实现任何他们想做的事情,或合乎常理,或匪夷所思,目的只在于解决他们在游戏中遇到的问题。
5)系统复杂性。可能会在一款游戏中包括多到无法估量的元素,例如地质、气候和生物分布,以及精细到皮肤、肌肉、血液、骨骼和脂肪的战斗系统,甚至战损痊愈后会留下伤疤以及后遗症。在有些游戏里则可能包括数百种的死亡原因,数千种的生物,数万种的物品。
Roguelike 地图生成算法
地图生成算法是这样一个黑盒,它需要你输入地图的限制规则和大小等信息,它的输出是具体的地图数据,具体到Roguelike游戏的地图生成算法,它有如下特点:
1)要同时有开放的房间和走廊,房间在Roguelike游戏中起着至关重要的作用,开放的空间可以让玩家有空间进行战斗,同时房间也可以通过不同的装饰风格来增强游戏场景的表现力。同时,这个地牢不应该完全由房间组成,玩家需要在游戏过程中有不同的感受,走廊会让他们有封闭感,同时增加游戏的策略性。
2)地图生成中部分参数是可调的,由于关卡的难度要有梯度,所以生成规则应该是可调的,理想的做法是将生成器的一些参数设置成可调,可以通过同一套代码生成不同风格和感觉的地牢。
3)地图不是完美的,完美的地图意味着两点之间只有唯一的一条通路,这样玩起来缺少乐趣。当玩家遇到一个死胡同的时候,必须要回溯到之前的路线去,然后寻找新的可探索的地方。游戏是一个决定和做出不同选择的过程。因此,过于完美的地图不能让游戏变得更有趣。
生成地图的具体步骤包括:
1)随机生成房间,保证房间之间不相互覆盖。
2)计算如何连接各个房间。
3)把房间之外的空地用迷宫填满,移除掉死胡同。
4)连接相连的迷宫和房间,增加少量连接。首先是生成房间,这个过程需要注意的是要检查房间之间不相互重叠,每一个房间的生成过程包括随机生成房间左下角坐标和尺寸,判断重叠与否,创建房间。需要注意的是横纵方向个数要保证为奇数。然后是生成迷宫,生成迷宫的过程可以抽象为树的生成,生成的过程为连接每一个节点。首先判断起点上下左右是否在一个方向有连接,不存在就需要将节点放入列表中,如果第一步完成后列表不为空,则将节点向列表中的某一个方向移动两格并将移动后的坐标压入栈中,重复第一步。如果列表为空,则弹出栈顶元素,直到栈为空时。对于每一个走廊的块,如果其四个方向中有3个为空,则把它删除,就可以移除死胡同了。连接迷宫和房间,需要把每个区域联系起来,首先随机找到一个点,连通合并两个区域,然后删除p以外所有能连通两个区域的点,继续第一步,直到所有区域连通,为所有连通区域创建走廊,使所有房间可以连通。
实现
1、地图参数初始化
//计算房间数量范围calculateRoomSize(size, cell){var max = Math.floor((size/cell) * 0.8);var min = Math.floor((size/cell) * 0.25);if (min < 2) {min = 2;}if (max < 2) {max = 2;}return [min, max];},//初始化地图initMap(){//地图宽高的格子this._width = 96this._height = 64this._options = {cellWidth: 10, //单元格宽cellHeight: 10, //单元格高roomWidth: [2,10], //房间个数范围roomHeight: [2,7], //房间个数范围};if (! this._options.hasOwnProperty("roomWidth")) {this._options["roomWidth"] = this.calculateRoomSize(this._width, this._options["cellWidth"]);}if (! this._options.hasOwnProperty("roomHeight")) {this._options["roomHeight"]=this.calculateRoomSize(this._height, this._options["cellHeight"]);}},//入口函数onLoad(){//初始化this.initMap()//地图生成this.mapGenerate()//绘制地图this.drawMap()},
地图生成主要根据如上三步进行,每一步都有一些需要注意的地方。当然,在做这些之前,首先需要进行地图数据的初始化,在这里首先初始化map数组,这是一个二维数组。用来存储最后地图表示的数据。首先把这个数组中的每一个值都初始化为0,也就是所有的位置都是空地,然后初始化房间和房间联通的数组
2、地图的初始化和生成步骤
//设置map数值,初始化为一个值fillMap(value) {var map = [];for (var i = 0; i < this._width; i ++){map.push([]);for (var j = 0; j < this._height; j ++){map[i].push(value);}}return map;},//初始化房间的数量initRooms() {for (var i = 0; i < this._options.cellWidth; i++) {this.rooms.push([]);for(var j = 0; j < this._options.cellHeight; j++) {this.rooms[i].push({"x":0, "y":0, "width":0, "height":0,"connections":[], "cellx":i, "celly":j});}}},//地图生成过程mapGenerate(){this.map = this.fillMap(0); //初始化地图数据this.rooms = []; //房间this.connectedCells = []; //连通的房间//初始化房间this.initRooms()//连接房间this.connectRooms()this.connectUnconnectedRooms()//创建房间this.createRooms()//创建走廊this.createCorridors()},
在initRooms函数里,只是初始化了房间数组,并没有创建房间的数据。生成房间的过程从connectRooms开始,首先连接房间,然后遍历一下房间,看看有没有“被遗忘”的角落,一定要确保所有房间都是连通的,这样才能避免死角的出现,最后才生成房间的数据,调用createRooms生成房间数据
3、生成房间和连接房间
//创建房间createRooms() {var w = this._width;var h = this._height;var cw = this._options.cellWidth;var ch = this._options.cellHeight;var cwp = Math.floor(this._width / cw);var chp = Math.floor(this._height / ch);//房间属性var roomw;var roomh;var roomWidth = this._options["roomWidth"];var roomHeight = this._options["roomHeight"];var sx;var sy;var otherRoom;//遍历房间中每一个点for (var i = 0; i < cw; i++) {for (var j = 0; j < ch; j++) {sx = cwp * i;sy = chp * j;if (sx == 0) {sx = 1;}if (sy == 0) {sy = 1;}//房间宽高,随机获得roomw = GlobalHandle.getRandomInt(roomWidth[0], roomWidth[1]);roomh = GlobalHandle.getRandomInt(roomHeight[0], roomHeight[1]);if (j > 0) {otherRoom = this.rooms[i][j-1];while (sy - (otherRoom["y"] + otherRoom["height"] ) < 3) {sy++;}}if (i > 0) {otherRoom = this.rooms[i-1][j];while(sx - (otherRoom["x"] + otherRoom["width"]) < 3) {sx++;}}var sxOffset = Math.round(GlobalHandle.getRandomInt(0, cwp - roomw)/2);var syOffset = Math.round(GlobalHandle.getRandomInt(0, chp - roomh)/2);while (sx + sxOffset + roomw >= w) {if(sxOffset) {sxOffset--;} else {roomw--;}}while (sy + syOffset + roomh >= h) {if(syOffset) {syOffset--;} else {roomh--;}}sx = sx + sxOffset;sy = sy + syOffset;this.rooms[i][j]["x"] = sx;this.rooms[i][j]["y"] = sy;this.rooms[i][j]["width"] = roomw;this.rooms[i][j]["height"] = roomh;//设置地图for (var ii = sx; ii < sx + roomw; ii++) {for (var jj = sy; jj < sy + roomh; jj++) {this.map[ii][jj] = 1;}}}}},
地图生成结果
小方块组成的即“房间”。可以发现,房间之间都互相独立,并不能互相连通,这就是后续我们要做的,即生成走廊。首先在数据上,参考之前生成的房间连通数据,生成走廊,随后在绘制走廊的函数里更新map数据。
//绘制走廊,设置map值drawCorridor(startPosition, endPosition) {var xOffset = endPosition[0] - startPosition[0];var yOffset = endPosition[1] - startPosition[1];var xpos = startPosition[0];var ypos = startPosition[1];var tempDist;var xDir;var yDir;var move;var moves = [];var xAbs = Math.abs(xOffset);var yAbs = Math.abs(yOffset);var percent = Math.random();var firstHalf = percent;var secondHalf = 1- percent;xDir = xOffset > 0 ? 2 : 6;yDir = yOffset > 0 ? 4 : 0;if (xAbs < yAbs) {tempDist = Math.ceil(yAbs * firstHalf);moves.push([yDir, tempDist]);moves.push([xDir, xAbs]);tempDist = Math.floor(yAbs * secondHalf);moves.push([yDir, tempDist]);} else {tempDist = Math.ceil(xAbs * firstHalf);moves.push([xDir, tempDist]);moves.push([yDir, yAbs]);tempDist = Math.floor(xAbs * secondHalf);moves.push([xDir, tempDist]);}this.map[xpos][ypos] = 2;while (moves.length > 0) {move = moves.pop();while (move[1] > 0) {xpos += GlobalHandle.DIRS[8][move[0]][0];ypos += GlobalHandle.DIRS[8][move[0]][1];this.map[xpos][ypos] = 2;move[1] = move[1] -1;}}},createCorridors() {//创建走廊var cw = this._options.cellWidth;var ch = this._options.cellHeight;var room;var connection;var otherRoom;var wall;var otherWall;for (var i = 0; i < cw; i++) {for (var j = 0; j < ch; j++) {room = this.rooms[i][j];for (var k = 0; k < room["connections"].length; k++) {connection = room["connections"][k];otherRoom = this.rooms[connection[0]][connection[1]];//获得墙体数量if (otherRoom["cellx"] > room["cellx"]) {wall = 2;otherWall = 4;} else if (otherRoom["cellx"] < room["cellx"]) {wall = 4;otherWall = 2;} else if(otherRoom["celly"] > room["celly"]) {wall = 3;otherWall = 1;} else if(otherRoom["celly"] < room["celly"]) {wall = 1;otherWall = 3;}this.drawCorridor(this.getWallPosition(room, wall),this.getWallPosition(otherRoom, otherWall));}}}},
生成地图数据后,接下来的任务就是把这个地图绘制出来,在drawMap中绘制,根据map里每个元素值对应的不同类型渲染不同颜色的方块。
//绘制地图drawMap(){for (var i = 0; i < this._width; i ++){for (var j = 0; j < this._height; j ++) {if(this.map[i][j] == 1){ //房间地图格var ctx = this.mapLayer.getComponent(cc.Graphics)ctx.fillColor.fromHEX('#FF0000');ctx.rect((i) * this._options.cellWidth, (j) *this ._options.cellHeight, this._options.cellWidth, this._options.cellHeight)ctx.fill()ctx.stroke()}else if(this.map[i][j] == 2){ //门口地图格var ctx = this.mapLayer.getComponent(cc.Graphics)ctx.fillColor.fromHEX('#7B68EE');ctx.rect((i) * this._options.cellWidth, (j) * this._options.cellHeight, this._options.cellWidth, this._options.cellHeight)ctx.fill()}else if(this.map[i][j] == 3) {//走廊地图格var ctx = this.mapLayer.getComponent(cc.Graphics)ctx.fillColor.fromHEX('#00FF00');ctx.rect((i) * this._options.cellWidth, (j) * this._options.cellHeight, this._options.cellWidth, this._options.cellHeight)ctx.fill()}}}},
结果
A星算法
,A星搜索算法用来实现敌人的智能运动,比如敌人巡逻或者角色寻径
相关文章:
地图之战争迷雾/地图算法/自动导航(一)
战争迷雾 TiledMap 创建黑色覆盖块,然后使用碰撞组件,控制黑色块的显示和隐藏 地图算法 在有些游戏中,地图需要随机生成,比如游戏中的迷宫等,这就需要地图生成的算法;在角色扮演类游戏中,角色…...
【wiki知识库】06.文档管理页面的添加--前端Vue部分
📝个人主页:哈__ 期待您的关注 目录 一、🔥今日目标 二、🐻前端Vue模块的改造 BUG修改 1.wangeditor无法展示问题 2.弹窗无法正常关闭问题 2.1 添加admin-doc.vue 2.1.1 点击admin-ebook中的路由跳转到admin-doc 2.2.2 进入…...
新电脑必装的7款软件,缺一不可
如果你买了新电脑或者是重装了新系统,那么这7款软件你一定要安装。 1、SpaceSniffer 如果你的C盘经常爆红,但是不知道是什么原因,那么你应该需要SpaceSniffer这款软件,它可以把你C盘中文件的空间占用情况,以大小方框…...
程序员学习Processing和TouchDesigner视觉编程相关工具
Proessing Processing 是一种用于视觉艺术和创意编程的开发环境和编程语言。它最初是为了帮助非专业程序员学习编程,特别是那些对于创意编程和视觉表达感兴趣的人。Processing 提供了简单易用的 API,使得绘制图形、创建动画和交互式应用变得相对容易。 …...
gitlabcicd-k8s部署gitlab
一.安装准备环境 存储使用nfs挂载持久化 k8s环境 helm安装 建议helm 3 二.部署gitlab-deploy.yaml nfs的ip是192.168.110.190 挂载目录是/data/data 注意所需要的目录需要创建:/data/data/gitlab/config ,/data/data/gitlab/logs ,/dat…...
浅谈JDBC
文章目录 一、什么是 JDBC?二、JDBC 操作流程三、JDBC代码例子 一、什么是 JDBC? JDBC是一种可用于执行SQL语句的JAVA API,是链接数据库和JAVA应用程序的纽带。JDBC一般需要进行3个步骤:与数据库建立一个链接、向数据库发送SQL语…...
【数据结构初阶】--- 顺序表
顺序表,好像学C语言时从来没听过,实际上就是给数组穿了层衣服,本质是一模一样的。 这里的顺序表实际是定义了一个结构体,设计各种函数来实现它的功能,比如说数组中的增删改查插入,这些基本操作其实平时就会…...
一个完整的java项目通常包含哪些层次(很全面)
1.View层(视图层) 职责:负责数据的展示和用户交互。在Web应用中,View层通常与HTML、CSS和JavaScript等技术相关。 技术实现:在Spring MVC中,View层可以使用JSP、Thymeleaf、FreeMarker等模板引擎来实现。…...
设置电脑定时关机
1.使用快捷键winR 打开运行界面 2.输入cmd ,点击确认,打开命令行窗口,输入 shutdown -s -t 100,回车执行命令,自动关机设置成功 shutdown: 这是主命令,用于执行关闭或重启操作。-s: 这个参数用于指定执行关…...
Java 编译报错:找不到符号? 手把手教你排查解决!
Java 编译报错:找不到符号? 手把手教你排查解决! 在 Java 开发过程中,我们经常会遇到编译器抛出 "找不到符号" 错误。这个错误提示意味着编译器无法在它所理解的范围内找到你所引用的类、变量或方法。这篇文章将带你一步…...
Gitte的使用(Windows/Linux)
Gitte的使用(Windows/Linux) 一、Windows上使用Gitte1.下载程序2.在Gitte上创建远程仓库3.连接远程仓库4.推送文件到远程仓库 二、Linux上使用Gitte1.第一次从仓库上传1.1生成公钥1.2配置SSH公钥1.3新建一个仓库1.4配置用户名和邮箱在Linux中1.5创建仓库…...
c++之旅第十弹——IO流
大家好啊,这里是c之旅第十弹,跟随我的步伐来开始这一篇的学习吧! 如果有知识性错误,欢迎各位指正!!一起加油!! 创作不易,希望大家多多支持哦! 一.流的概念&…...
量化交易:Miniqmt获取可转债数据和交易python代码
哈喽,大家好,我是木头左! 低风险资产除了国债外,还有可转债,兼容有高收益的股性和低风险的债性,号称“下有保底,上不封顶”。 🔍 可转债:金融市场的双面娇娃 可转债&am…...
测试开发之自动化篇 —— 使用Selenium IDE录制脚本!
今天,我们开始介绍基于开源Selenium工具的Web网站自动化测试。 Selenium包含了3大组件,分别为:1. Selenium IDE 基于Chrome和Firefox扩展的集成开发环境,可以录制、回放和导出不同语言的测试脚本。 2. WebDriver 包括一组为不同…...
Django 外键关联数据
在设计数据库的时候,是得需要通过外键的形式将各个表进行连接。 原先的表是这样的 要想更改成这样: 下面是操作步骤: 有两张表是关联的 # 在 models.py 里创建class Department(models.Model):"""部门表""&quo…...
开源与新质生产力
在这个信息技术迅猛发展的时代,全球范围内的产业都在经历着深刻的变革。在这样的背景下,“新质生产力”的概念引起了广泛的讨论。无论是已经成为或正努力转型成为新质生产力的企业,都在寻求新的增长动力和竞争优势。作为一名长期从事开源领域…...
如何将 Windows图片查看器的背景颜色改成浅色(灰白色)?
现在大家基本都在使用Win10系统,我们在双击查看图片时,系统默认使用系统自带的图片(照片)查看器去打开图片。图片查看器的背景色默认是黑色的,如下所示:(因为大家可能会遇到同样的问题ÿ…...
k8s-pod参数详解
目录 概述创建Pod编写一个简单的Pod添加常用参数为Pod的容器分配资源网络相关Pod健康检查启动探针存活探针就绪探针 作用整个Pod参数配置创建docker-registry 卷挂载 结束 概述 k8s中的pod参数详解。官方文档 版本 k8s 1.27.x 、busybox:stable-musl、nginx:stable-alpine3…...
一些计算机网络面试题
TCP建立连接和关闭连接的流程?每个流程的环节? TCP是在传输层的协议,建立的是可靠传输 TCP在传输数据前建立连接是采用三次握手,关闭连接是四次挥手 三次握手:因为目前网络通讯是全双工的,那我假设浏览器…...
transformer - 注意力机制
Transformer 的注意力机制 Transformer 是一种用于自然语言处理任务的模型架构,依赖于注意力机制来实现高效的序列建模。注意力机制允许模型在处理一个位置的表示时,考虑输入序列中所有其他位置的信息,而不仅仅是前面的几个位置。这种机制能…...
三端植物大战僵尸杂交版来了
Hi,好久不见,最近植物大战僵尸杂交版蛮火的 那今天苏音整理给大家三端的植物大战僵尸杂交版包括【苹果端、电脑端、安卓端】 想要下载的直接划到最下方即可下载。 植物大战僵尸,作为一款古老的单机游戏,近期随着B站一位UP主潜艇…...
np.hstack()和np.vstack()函数解释
np.hstack()和np.vstack()函数解释 文章目录 1,np.hstack()1.1,代码1.2,结果 2,np.vstack()2.1,代码2.2,结果 3,np.hstack()和np.vstack()3.1,代码3.2,结果 1,…...
【Linux】进程5——进程优先级
1.进程优先级 1.1.什么是进程优先级 cpu资源分配的先后顺序,就是指进程的优先权(priority)。优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上&#x…...
CNN简介与实现
CNN简介与实现 导语整体结构卷积层卷积填充步幅三维卷积立体化批处理 实现 池化层特点实现 CNN实现可视化总结参考文献 导语 CNN全称卷积神经网络,可谓声名远扬,被用于生活中的各个领域,也是最好理解的神经网络结构之一。 整体结构 相较于…...
【AI大模型】Transformers大模型库(五):AutoModel、Model Head及查看模型结构
目录 一、引言 二、自动模型类(AutoModel) 2.1 概述 2.2 Model Head(模型头) 2.3 代码示例 三、总结 一、引言 这里的Transformers指的是huggingface开发的大模型库,为huggingface上数以万计的预…...
Hadoop yixing(移行),新增表字段,删除表字段,修改存储格式
Hadoop yixing(移行),新增表字段,删除表字段,修改存储格式 一、hadoop中修改存储格式,比如从 textfile 转化为 orc 格式,表中的数据的组织形式要重新改变,就要将重新创建新格式的表将原来的数据按照新的格…...
使用汇编和proteus实现仿真数码管显示电路
proteus介绍: proteus是一个十分便捷的用于电路仿真的软件,可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域,使用代码实现电路功能的仿真。 汇编语言介绍: 百度百科介绍如下: 汇编语言是培养…...
【Unity】官方文档学习-光照系统
目录 1 前言 2 光照介绍 2.1 直接光与间接光 2.2 实时光照与烘焙光照 2.3 全局光照 3 光源 3.1 Directional Light 3.1.1 Color 3.1.2 Mode 3.1.3 Intensity 3.1.4 Indirect Multiplier 3.1.5 Shadow Type 3.1.6 Baked Shadow Angle 3.1.7 Realtime Shadows 3.1…...
1731. 每位经理的下属员工数量
1731. 每位经理的下属员工数量 题目链接:1731. 每位经理的下属员工数量 代码如下: # Write your MySQL query statement below select a.employee_id as employee_id,a.name as name,count(b.employee_id) as reports_count,round(avg(b.age),0) as av…...
特征筛选LASSO回归封装好的代码、数据集和结果
Gitee仓库地址:特征筛选LASSO回归封装好的代码、数据集和结果 README LassoFeatureSelector_main 这个是主函数文件,在实例化LassoFeatureSelector类时,需要传入下面这些参数: input_train_data_path:输入训练集的路…...
郴州市地图/百度搜索关键词优化
近年来,越来越多的人加入了测试大军中,很多人也想通过自学来学习软件测试技术加入这个行业,但是现在软件测试的书籍越来越多,也良莠不齐,而且软件测试涉及的技术也越来越多。鉴于此情况,为了回馈大家&#…...
顶级复刻手表网站/推蛙网络
转载于:https://www.cnblogs.com/viplued/p/7765149.html...
网站开发给网站设置图标在什么文件中写代码/nba最新交易新闻
需要实现的效果如图,当光标停留在System上时出现文档说明,以下jdk1.8举例 实现: 1、先下载一个jdk api 1.8_google.CHM文件 2、cmd中执行命令 先进入该目录下,然后执行下面命令,其中html1.8文档可以自定义࿰…...
小破站下载/seo搜索优化培训
导读有时我们会在网上下载一些proe或者Creo模型,由于不知道这些模型具体版本,使用软件打开时可能会在信息栏提示“xxx不能检索”,这是因为Proe和Creo的低版本是无法打开高版本的。难道我们必须需要安装高版本的软件吗?我只是想欣赏一下模型而…...
搬瓦工如何搭建做网站/营销软文代写
前提是你的电脑和手机都已经安装了frida并运行正常。 如果你还没安装frida,请参考文章 Android逆向_使用frida 安装frida环境。这里使用国外大佬写的js脚本,来追踪app的方法调用,首先看一下效果:*** entered com.test.flyer.MainActivity.tes…...
发明迷网站豆渣做豆腐/seo关键词排名软件流量词
最近一位想跳槽大厂的老程序员朋友面试了几家发现:6年前面试最常问的并且可以顺利拿到高薪的技能是 Dubbo ,2年前面试,只要你简历上有 Spring Cloud 项目的相关经验,肯定会打动面试官,现在呢?简历上有Dubbo和简单的Spr…...