30分钟简易复刻元气骑士地图生成系统
本文转自Unity Connect博主 超级汽水
一个简易的房间类 Roguelike 游戏地图生成系统
如果你还不知道《元气骑士》是什么游戏,也许你可以去看看这个视频
https://space.bilibili.com/87721937
地图显示方式
- 随机大小的矩形房间。
- 随机的房间数量。
- 通过走廊连接每个房间。
- 每个图都有 俩个特殊房间:“出生房”、“传送房”。
地图生成思路梳理
- 因为在原版游戏中房间并不是完全的正方形,所以我们在设计时要考虑到边长的问题。
- 虽然游戏中的房间数量是随机的,但是也是有一个范围的。所以需要按照生成地图的最终面积来做一个约束。
- 走廊连接算是游戏中的一个难点,因为走廊的长度是不确定的要在生成房间后根据房间的位置和大小来确定走廊的生成位置以及长度。
- 在游戏中,每一个大关卡包含多个小关卡,每个小关卡中又包含了多张地图,每个地图中又有多个小房间。这样说可能有点不太好理解我画了张图来帮忙理解:
实现思路以及简化
在之前已经发过俩篇文章介绍tilemap生成随机地图的方法,如果对tilemap不太了解可以先去看看:
使用tilemap制作随机地图(1)
使用tilemap制作随机地图(2)
整体的实现流程如下:
1 .根据用户定义创建一张足够大的地图 (这里的地图指每个小关所有房间所在的大地图)。
2 .假设大地图中所有位置布满大小相同的房间 (这里的房间边长一定要奇数,比较好操作),然后根据所需的房间总数来删掉多余的房间。
3 .根据规定的长宽比,来随机修改每个房间的大小。
4 .生成过道连通所有房间,(这里黄色的点是原先没有改变大小时的正方形的中心点)
5 .确定特殊房间的位置。
Tilemap中单独房间效果图:
一个简单的房间以及半个过道
长方形连接正方形房间,黄色方块为中心点
Unity中详细操作
创建一个普通的Tilemap。
创建一个空物体,用来挂载我们的地图生成脚本。
创建所需要的变量
public class MapManager : MonoBehaviour
{[Header("地图种子")] public int seed = 123456;[Header("每行房间数")] public int mapMaxW;[Header("每列房间数")] public int mapMaxH;[Header("总生成房间数")] public int mapCount;[Header("最大房间宽")] public int roomMaxW;[Header("最大房间高")] public int roomMaxH;[Header("最小房间宽")] public int roomMinW;[Header("最小房间高")] public int roomMinH;[Header("房间的间隔距离")] public int distance;[Header("地板")] public TileBase floor;[Header("墙")] public TileBase wall;[Header("地图")] public Tilemap tilemap;private int[,] _roomMap;private List<Vector3Int> _centerPoint;private Dictionary<Vector3Int,int> _mapPoint;
}
- 列出所需函数
//画出地图
private void DrawMap(){}
//画出房间
private void DrawRoom(int roomX,int roomY){}
//画出路
private void DrawRoad(){}
//画出地板和墙壁
private void DrawFloor(){}
//生成房间 (用二维 int 数组表示)
private int[,] RandomRoom(int maxW, int maxH, int minW, int minH, out int width, out int height){}
//生成一个地图 (用二维 int 数组表示)
private int[,] GetRoomMap(int mapW, int mapH, int roomCount)
//获取一个范围内的随机奇数
private int GetOddNumber(int min, int max){}
//获取下一个房间的位置
private Vector2Int GetNextPoint(Vector2Int nowPoint, int maxW, int maxH)
5 .实现各个函数
代码已经放在文末的附件,这里我讲一下我的大体思路以及各个函数的作用
首先是使用,我在 Update 函数中检测按下 R 键重新生成地图,生成很简单只要调用 DrawMap 函数就可以
private void Update()
{if (Input.GetKeyDown(KeyCode.R)){DrawMap();}
}在 DrawMap 中 会调用 DrawRoad 和 DrawFloor 俩个函数来分别画出道路和地板、墙壁。
部分函数解析:
//取一定范围内的一个奇数
private int GetOddNumber(int min, int max)
{while (true){var temp = Random.Range(min, max);if ((temp & 1) != 1) continue;return temp;}
}这个函数主要用来在房间生成的时候取一个随机的奇数出来,因为我们的房间连接需要一个中心点所以奇数更方便使用。
//生成一个房间,用二维 int 数组表示
private int[,] RandomRoom(int maxW, int maxH, int minW, int minH, out int width, out int height)
{width = GetOddNumber(minW, maxW);height = GetOddNumber(minH, maxH); var room = new int[width, height];//方便以后扩展使用了二维数组,这里为了演示方便对房间内生成其他物体for (var i = 0; i < width; i++){for (var j = 0; j < height; j++){room[i, j] = 1;}}return room;
}这个函数主要用来生成一个房间,选用二维int数组主要是为了扩展、存储时方便。本案例中 普通地板为 1,墙壁为 0。同时为了后续步骤计算方便这里把生成的房间的长宽也返回了。
private int[,] GetRoomMap(int mapW, int mapH, int roomCount)
{//第一个房间的坐标点var nowPoint = Vector2Int.zero;//当前生成的房间数var mCount = 1;//当前地图var map = new int[mapW, mapH];//第一个格子总有房间,作为出生房间map[nowPoint.x, nowPoint.y] = 1;while (mCount < roomCount){nowPoint = GetNextPoint(nowPoint, mapW, mapH);if (map[nowPoint.x, nowPoint.y] == 1) continue;map[nowPoint.x, nowPoint.y] = 1;mCount ++;}return map;
}这个函数用来生成总体的地图,也就是用来查看哪里需要生成房间。需要生成房间的地方为 1 ,空白的地方为 0。与GetNextPoint 连用获取下一个房间的坐标点。因为房间总是相连所以不存在间隔。private Vector2Int GetNextPoint(Vector2Int nowPoint, int maxW, int maxH)
{while (true){var mNowPoint = nowPoint;switch (Random.Range(0, 4)){case 0:mNowPoint.x += 1;break;case 1:mNowPoint.y += 1;break;case 2:mNowPoint.x -= 1;break;default:mNowPoint.y -= 1;break;}if (mNowPoint.x >= 0 && mNowPoint.y >= 0 && mNowPoint.x < maxW && mNowPoint.y < maxH){return mNowPoint;}}
}这个函数大体的思想还是参照我前俩篇文章中讲到的随机游走法的思路。
最终效果 :
1 .生成房间
2 .添加横向过道
3 .添加纵向过道
4 .添加墙壁
原文链接:https://connect.unity.com/p/30fen-zhong-jian-yi-fu-ke-yuan-qi-qi-shi-di-tu-sheng-cheng-xi-tong?app=true
更多干货,戳上方链接下载Unity官方app,在线互动答疑技术社区,学习交友两不误!
30分钟简易复刻元气骑士地图生成系统相关推荐
- 元气骑士 自建服务器,30分钟简易复刻《元气骑士》地图生成系统
对<元气骑士>这款游戏想必大家都不陌生. 元气骑士是由凉屋游戏工作室研发的一款角色扮演类游戏,于2017年2月17日发布. 游戏讲述了外星生物夺走维持世界的魔法石的故事,玩家将扮演骑士.刺 ...
- AI帮60年代老技术解决面料数字化难题,王华民团队新方法只需3分钟数据采集复刻面料真实效果...
杨净 发自 凹非寺 量子位 | 公众号 QbitAI 当人人谈论元宇宙时,大家都在关心什么?空间是否热闹丰富,交互是否丝滑-- NoNoNo其实都不是,而是真实感与沉浸感. △饱受批评的小扎自拍 作为 ...
- 面试官问:生成订单30分钟未支付,则自动取消,该怎么实现?
欢迎关注方志朋的博客,回复"666"获面试宝典 来源 | https://blog.csdn.net/hjm4702192/article/details/80519010 在开发 ...
- 订单30分钟未支付自动取消怎么实现?
本文已经收录到Github仓库,该仓库包含计算机基础.Java核心知识点.多线程.JVM.常见框架.分布式.微服务.设计模式.架构等核心知识点,欢迎star~ 地址:https://github.co ...
- 面试官:生成订单30分钟未支付,则自动取消,该怎么实现?
Hollis的新书限时折扣中,一本深入讲解Java基础的干货笔记! 目录 了解需求 方案 1:数据库轮询 方案 2:JDK 的延迟队列 方案 3:时间轮算法 方案 4:redis 缓存 方案 5:使用 ...
- 实现生成订单30分钟未支付,则自动取消
目录 了解需求 方案 1:数据库轮询 思路 实现 优点 缺点 方案 2:JDK 的延迟队列 思路 实现 优点 缺点 方案 3:时间轮算法 思路 实现 优点 缺点 方案 4:redis 缓存 思路一 实 ...
- 再见了,程序员!钢铁工人用低代码30分钟开发一套核酸登记软件
作者| Mr.K 编辑| Emma 来源| 技术领导力(ID:jishulingdaoli) 最近看到一则新闻: 近期,广西防城港市出现疫情,全市展开一轮大规模核酸检测.柳钢工人彭期文在钉钉上仅用 ...
- 【工作教程】在本地复刻PM系统的过程记录(一)
为什么要复刻? 公司的PM系统很垃圾,很多查询并不自由.而且慢的一批.你可以理解很多数据库的底层逻辑,以及整个系统之所以蛋疼的地方. 需要的准备 Excel 会使用excel的power query以 ...
- 生成订单30分钟未支付,则自动取消,该怎么实现?(典藏版)
目录 方案分析 (1)数据库轮询 (2)JDK的延迟队列 (3)时间轮算法 (4)redis缓存 (5)使用消息队列 在开发中,往往会遇到一些关于延时任务的需求.例如 生成订单30分钟未支付,则自动取 ...
最新文章
- CentOS7 yum 源的配置与使用
- 多线程下载问题(IDHTTP)
- Ubuntu上安装Air运行时和Air程序
- MySQL5.7.12新密码登录方式及密码策略
- HDU4364(模拟矩阵乘法)
- CSS3基础知识(一)
- 如何写一篇合格的论文(清华大学刘知远)
- 计算机比特块的输出概念,第1讲-比特的概念及计算机的组成原理.ppt
- json 取值判断_对应后台传json ajax 获取值判断
- 敏捷开发用户故事系列之六:用户故事的产生与组织结构
- Bootstrap3学习笔记
- eclipse找不到arm-linux-gcc,使用 Eclipse 和 ARM GCC 搭建 STM32 开发环境
- android sqlite数据库代码,android sqlite数据库代码
- 在线免费一键将头像转换卡通形象
- Redis 各种用法总结,你知道几种?
- MobaXterm连接虚拟机Ubuntu
- Sigmoid Function
- ValueError: source code string cannot contain null bytes
- 使用docker中容器的坑
- 计算今天是今年的第几周