前言

最近刚确定下来毕业设计要做的内容——一个2DRoguelike类型的游戏。因此研究了几天的地图生成算法,终于于如今成功制作了地图的生成。先放几张示意图感受一下:



是不是还蛮有感觉的呢!

一、核心思路

首先我们要明白的是一点。地图的随机生成方法有很多,但是前提是必须要保证这些地图区域的复杂性和连通性。因此虽然随机生成难度不大,但是合理性还是需要考虑的。

大体思路是这样的:
1.首先我们要随机生成一些墙和通路。这些是完全随机的。当然最外圈是必然是墙的。
2.接下来对这些完全随机生成的方块按照一定规则进行反复处理。
3.在完全处理过后,会生成一些并不连通的区域,打通他们。
4.在生成入口和出口。

二、随机生成墙和通路

这一段没什么好说的。不过如果按照我的算法来做的话,这个初始随机是墙和通路的概率是多少并无什么太大关系。我分别测试了20%、50%、80%的概率初始生成墙,发现最终的地图区别并没有什么明显的区别。
我的地图是15*15的。首先我定义了一个Map类。它代表着每一个地图的格子。当然这个类我的名字起的并不好,不过我也想不出什么更好的名字了,所以就干脆不变了。这个Map类里面包含这些属性:

public int type = 0;//0通路 1墙 2复活点 3上楼点public int RoundWallCount = 0;public int x;public int y;//数据结构public bool IsVisited = false;

type代表的是当前格子的类型。RoundWallCount指的则是当前格子周围的墙(type==1)的数量。x和y指的是当前格子的坐标。至于IsVisited在后面的打通部分有用处。
首先定义一个Map[,]的二维数组。作为我当前的全部地图。然后对这个地图进行初始化,完全生成一个15*15的地面。

        Object OFloor = Resources.Load("Prefabs/Floor", typeof(GameObject));for(int x = 0; x < 15; x++){for(int y = 0; y < 15; y++){GameObject GO = Instantiate(OFloor, PFloor) as GameObject;GO.transform.position = new Vector3(x, y, 0);}}

这些地面是完全不需要规则的,只管生成就好。接下来就需要随机生成墙了。

 for (int x = 0; x < 15; x++){for (int y = 0; y < 15; y++){Map[x, y] = new Map();Map[x, y].x = x;Map[x, y].y = y;if (Random.Range(0, 100) < 50 ||x == 0 || y == 0 || x == 14 || y == 14){Map[x, y].type = 1;}}}

当然我的type的默认值是0.所以如果不是墙,那么并不需要赋值。
我放几张图表示一下这个算法生成的结果

二、循环处理地图

这时候我们发现这张图虽然有点感觉,但是不连通的区域实在是太多了。所以我们要进行一系列算法来修改地图,使这张地图尽可能地连通。
核心算法是这样的。反复进行以下操作:
1.取当前每一个格子周围的墙的数量
2.如果当前格子是墙,那么当他周围的墙<5个或者大于7个时,将其转变为路面
3.如果当前格子是路,那么当他周围的墙>=4个或者小于2个时,把他变成墙

  for (int i = 0; i < 3; i++){//记录墙的数量for (int x = 1; x < 14; x++){for (int y = 1; y < 14; y++){//检查周围一圈墙的数量Map[x, y].RoundWallCount = 0;for (int tx = x - 1; tx < x + 2; tx++){for (int ty = y - 1; ty < y + 2; ty++){if (Map[tx, ty].type == 1){Map[x, y].RoundWallCount += 1;}}}}}//修改地形for (int x = 1; x < 14; x++){for (int y = 1; y < 14; y++){if (Map[x, y].type == 1){if (Map[x, y].RoundWallCount < 5 || Map[x, y].RoundWallCount > 7
) {Map[x, y].type = 0;}}else{if (Map[x, y].RoundWallCount >= 4 || Map[x, y].RoundWallCount < 2) {Map[x, y].type = 1;}}}}}

接下来我们会得到类似于这样的一张图


可以看到大体而言,这张图会变得大块更加少一些,细碎的小路更加多一些。而且总体而言并没有之前那么多不连通的区域了。

三、打通所有不连通的区域

首先为了打通区域,我们要划分开哪些是同一个区域。这里我要感谢一下我的一个朋友。在我还在想深度优先遍历迷宫寻路的时候,他提供了一个相当棒的思路。只需要找到一个点,把这个点标为已访问。然后找寻他周围四个点是否是未访问的路,然后把他们加入。再查找他们周围的点。直到最后你的最后一个点四周并无新增点。整体就为一个区域。
我对区域的定义是这样的:

public class Area
{public List<Map> MapList = new List<Map>();
}

一个含有Map的List变量的一个类。
接下来就是划分区域的代码了:

     List<Map> RoadList = new List<Map>();List<Area> AreaList = new List<Area>();//初始化RoadListfor (int x = 1; x < 14; x++){for (int y = 1; y < 14; y++){if (Map[x, y].type == 0){RoadList.Add(Map[x, y]);}}}//区分Areawhile (RoadList.Count > 0){if (RoadList.Count == 1){Area area = new Area();area.MapList.Add(RoadList[0]);AreaList.Add(area);break;}else{Area area = new Area();area.MapList.Add(RoadList[0]);for (int i = 0; i < area.MapList.Count; i++) {int x = area.MapList[i].x;int y = area.MapList[i].y;area.MapList[i].IsVisited = true;if (Map[x + 1, y].type == 0 && Map[x + 1, y].IsVisited == false){area.MapList.Add(Map[x + 1, y]);}if (Map[x - 1, y].type == 0 && Map[x - 1, y].IsVisited == false){area.MapList.Add(Map[x - 1, y]);}if (Map[x, y + 1].type == 0 && Map[x, y + 1].IsVisited == false){area.MapList.Add(Map[x, y + 1]);}if (Map[x, y - 1].type == 0 && Map[x, y - 1].IsVisited == false){area.MapList.Add(Map[x, y - 1]);}}foreach(Map m in area.MapList){foreach(Map ma in RoadList){if (m == ma){RoadList.Remove(ma);break;}}}AreaList.Add(area);}}

当你划分好区域之后,你就可以对这些区域进行打通操作。我这里采用了一种粗暴的打通方式:
在区域>1个时无限循环
1.寻找前两个区域之间最近的两个点
2.先横向打通,再纵向打通
3.合并这两个区域为1个区域
4.继续循环
上代码:

while (AreaList.Count > 1){int tempdis = 99;Map Start = null, End = null;foreach(Map m in AreaList[0].MapList){foreach(Map ma in AreaList[1].MapList){if(Mathf.Abs(m.x-ma.x)+ Mathf.Abs(m.y - ma.y) < tempdis){tempdis = Mathf.Abs(m.x - ma.x) + Mathf.Abs(m.y - ma.y);Start = m;End = ma;}}}if (Start.x < End.x){for(int x = Start.x; x < End.x; x++){Map[x, Start.y].type = 0;}if(Start.y < End.y){for (int y = Start.y; y < End.y; y++){Map[End.x, y].type = 0;}}else{for (int y = Start.y; y > End.y; y--){Map[End.x, y].type = 0;}}}else{for (int x = Start.x; x > End.x; x--){Map[x, Start.y].type = 0;}if (Start.y < End.y){for (int y = Start.y; y < End.y; y++){Map[End.x, y].type = 0;}}else{for (int y = Start.y; y > End.y; y--){Map[End.x, y].type = 0;}}}foreach(Map m in AreaList[1].MapList){AreaList[0].MapList.Add(m);}AreaList.Remove(AreaList[1]);           }

OK!大功告成。最后你就会得到如开头所说的比较好看的完全随机地图啦!

四、生成起始点和终点

这里我使用了一种并不完全随机的算法。我首先在周围一圈随机寻找一个通路,把他设置为起始。如果这一圈都没有,那么再往里找一圈。直至找到为止。终点则是寻找最远的点然后设置为终点。

//生成起点int tempx=0, tempy=0;int Startx = 0,Starty = 0;for(int i = 1; i < 6; i++){List<Map> temp = new List<Map>();for(int x = i; x < 15 - i; x++){if (Map[x, i].type == 0){temp.Add(Map[x, i]);}if (Map[x, 14 - i].type == 0){temp.Add(Map[x, 14 - i]);}}for (int y = i; y < 15 - i; y++){if (Map[i, y].type == 0){temp.Add(Map[i, y]);}if (Map[14 - i, y].type == 0){temp.Add(Map[14 - i, y]);}}if (temp.Count > 0){int a = Random.Range(0, temp.Count);Map maptemp = temp[a];maptemp.type = 2;tempx = maptemp.x;tempy = maptemp.y;Object DF = Resources.Load("Prefabs/DF", typeof(GameObject));GameObject GO = Instantiate(DF, PFloor) as GameObject;GO.transform.position = new Vector3(maptemp.x, maptemp.y, 0);GOMap[maptemp.x, maptemp.y] = GO;Startx = maptemp.x;Starty = maptemp.y;break;}}//生成终点List<Map> RoadList = new List<Map>();for (int x = 1; x < 14; x++){for (int y = 1; y < 14; y++){if (Map[x, y].type == 0){RoadList.Add(Map[x, y]);}}}RoadList.Remove(Map[Startx, Starty]);int tempdis = 0;Map TempMap = null;foreach (Map m in RoadList){if (Mathf.Abs(m.x - Startx) + Mathf.Abs(m.y - Starty) > tempdis){tempdis = Mathf.Abs(m.x - Startx) + Mathf.Abs(m.y - Starty);TempMap = m;}}TempMap.type = 3;Object UF = Resources.Load("Prefabs/UF", typeof(GameObject));GameObject GO2 = Instantiate(UF, PFloor) as GameObject;GO2.transform.position = new Vector3(TempMap.x, TempMap.y);GOMap[TempMap.x, TempMap.y] = GO2;

结语

这种算法据说来源于计算机图形学。其实我刚开始写他的时候是不太了解的,仅仅在看了这个文章之后我在此基础上修改和添加了一些不同的算法,形成的我的地图算法。后来又查阅了很多资料,问了朋友,才最终确定这个算法。学无止境,各位加油。

一种简单的2D Roguelike地图生成算法相关推荐

  1. 波函数坍缩 地图生成-算法过程可视化(2D)

    波函数坍缩(Wave Function Collapse)生成 ,是一个随机程序化的生成算法,比较经典的是用在游戏场景的地图生成.想要了解详细的解读可以参考<波函数坍缩算法>的无限城市- ...

  2. 生成三角网算法java,一种低效但逻辑简单清晰的Delaunay三角网生成算法

    由离散样本点生成Delaunay三角网有多种算法,每个算法的执行效率都不一样,这里介绍一种最简单,最低效,但是算法逻辑最清晰的一种. Delaunay三角网必须满足的一个条件是任何一个三角形的外接圆都 ...

  3. android 2d瓷砖地形,2D游戏地图地表生成技术.pdf

    2D游戏地图地表生成技术.pdf 2D游戏地图地表生成技术 杨涛,秦可,吴飞,庄越挺 (浙江大学人工智能研究所,浙江,杭州310027,0571 wufei@cS.zju.edu.cn,yzhuang ...

  4. Unity 2D随机地图

    最近翻起以前下载的一些老的教学视频,于是决定重新看一遍,且每周所学做个记录,下面就直接开始. 这篇文章就讲讲教程里面的随机2D地图的实现原理,以及代码展示. 首先效果如下: 右边是使用UntiyEdi ...

  5. 随机地图生成--自己的一次尝试

    最近照着网上的元胞自动机随机地图生成算法自己尝试着写了一下,发现效果不是很满意 local count1 = Tile_map.CheckNeighborWall(i,j)--1层墙的数量 local ...

  6. 一个简单的2DRoguelike游戏随机地图生成思路

    首先我们要先明确一张Roguelike地图里包含的最基本元素是什么,我的理解是房间与通道.我们可以将一张地图抽象成是房间与房间通过通道来连接. 那么基于这个大前提,我的思路如下. 以图中红色格子为中心 ...

  7. [Unity]Roguelike随机地图生成(一)

    初步随机地图生成 基础房间生成 房间门的判断 基础房间生成 首先需要确定每次房间生成都是在上一个房间的哪个方向上生成,为此需要声明一个枚举值来记录上下左右四个方向 创建脚本RoomGenerator, ...

  8. “以撒的结合”地图是怎样生成的——RogueLike地图随机生成

    RogueLike地图随机生成 挺喜欢玩<以撒的结合>的,觉得游戏里房间的随机生成挺有意思 刚好在写一个自己的RogueLike游戏,就想着来复刻一下 首先来看一下<以撒的结合> ...

  9. 四维图新地图坐标_一种融合双目视觉和差分卫星定位的地标地图生成方法与流程...

    本发明属于地图测绘技术领域,更为具体地讲,涉及一种融合双目视觉和差分卫星定位的地标地图生成方法. 背景技术: 地标地图是一种将地图去除冗余信息以轻量化形式存储的高精度地图,可以为智能车提供部分静态目标 ...

最新文章

  1. 阿里云域名备案时产品类型
  2. 【职场建议】开发转算法,我们应该如何准备(过来人的肺腑之言)
  3. hdu 5256 序列变换 (LIS变形)
  4. 最优化读书笔记R(一)
  5. OLTP v.s. OLAP
  6. PIL图像处理时使用np.unit8转化报错: Cannot handle this data type: (1, 1), |O
  7. Java的表达式和运算符
  8. matlab仿真介绍,谈一谈|Matlab仿真项目简介
  9. arduino 有源 蜂鸣器_arduino实验–有源蜂鸣器报警
  10. python如何下载pdfminer_在python中使用PDFMiner从PDF文件中提取文本?
  11. java rrd 读取_rrd4j的使用详解1–数据保存入rrd文件 | 学步园
  12. 大一计算机课总结400字,第一学月总结400字以上
  13. C语言内存空间分布详解
  14. 树莓派用iPad做显示器
  15. 每天一个编程题·iOS开发算法提升计划(1)
  16. AndroidID、IMEI、OAID获取
  17. exlsx表格教程_e某cel表格~的各种基本操作.doc 文档全文预览
  18. c语言0x1234占两个字节,C语言考试必考知识点
  19. 《机器学习实战》学习笔记(八):预测数值型数据 - 回归
  20. 请广大编程爱好者加入QQ群5907439

热门文章

  1. 使用canvas对图片进行裁切
  2. 辛普森复合求积公式matlab,MATLAB数值分析实验二(复合梯形、辛普森和龙贝格求积,以及二重积分计算等).doc...
  3. 有哪些你一打开,就令你惊讶的网站?
  4. 此beta版已额满_日志MIUI 11 第439周开发版内测日志补充
  5. 推荐算法(一)——音乐歌单智能推荐
  6. 开关电源环路补偿设计及调节笔记
  7. 前端模板template-web简单使用
  8. JSoup模拟登录新版正方教务系统(内网-教务系统)获取信息过程详解
  9. 猿创征文| 我的开发者工具箱之数据分析师装备库
  10. 【IoT-卫朋】智能硬件 | 产品按键设计