Unity_Dungeonize 随机生成迷宫
本文对随机生成迷宫的实现思路进行记录,其作用在于为游戏过程提供随机性以及节省开发周期,下面是Dungeonize的结构
随机迷宫的生成主要包括几个阶段
1.生成房间体结构,为墙体,自定义房间,自定义物体生成平台
for (var i = ; i < room_count; i++) {
Room room = new Room ();
if (rooms.Count == ) {
//初始房间生成玩家和任务事件监听
room.x = (int)Mathf.Floor (map_size / 2f);
room.y = (int)Mathf.Floor (map_size / 2f); //Random.Range(10,20);
room.w = Random.Range (min_size, max_size);
if (room.w % == ) room.w += ;
room.h = Random.Range (min_size, max_size);
if (room.h % == ) room.h += ;
room.branch = ;
lastRoom = room;
} else {
int branch = ;
if (collision_count == ) {
branch = Random.Range (, ); //complexity
}
room.branch = branch; lastRoom = rooms [rooms.Count - ];
int lri = ; while (lastRoom.dead_end) {
lastRoom = rooms [rooms.Count - lri++];
} if (direction == "set") {
string newRandomDirection = directions[Random.Range(, directions.Count)];
direction = newRandomDirection;
while (direction == oldDirection)
{
newRandomDirection = directions[Random.Range(, directions.Count)];
direction = newRandomDirection;
} }
this.roomMarginTemp = Random.RandomRange(, this.roomMargin - );
//邻接方位生成房间
if (direction == "y") {
room.x = lastRoom.x + lastRoom.w + Random.Range (, ) + this.roomMarginTemp;
room.y = lastRoom.y;
} else if (direction == "-y") {
room.x = lastRoom.x - lastRoom.w - Random.Range (, ) - this.roomMarginTemp;
room.y = lastRoom.y;
} else if (direction == "x") {
room.y = lastRoom.y + lastRoom.h + Random.Range (, ) + this.roomMarginTemp;
room.x = lastRoom.x;
} else if (direction == "-x") {
room.y = lastRoom.y - lastRoom.h - Random.Range (, ) - this.roomMarginTemp;
room.x = lastRoom.x;
} room.w = Random.Range (min_size, max_size);
if (room.w % == ) room.w += ; room.h = Random.Range (min_size, max_size);
if (room.h % == ) room.h += ; room.connectedTo = lastRoom;
}
在随机产生生成房间体后,生成墙体形成一个完整的房间结构,为之后prefab提供空间
//wall
for (int x = ; x < map_size_x -; x++) {
for (int y = ; y < map_size_y -; y++) {
if (map [x, y].type == ) {
if (map [x + , y].type == || map [x + , y].type == ) { //west
map [x, y].type = ;
map [x, y].room = map [x + , y].room;
}
if (x > ) {
if (map [x - , y].type == || map [x - , y].type == ) { //east
map [x, y].type = ;
map [x, y].room = map [x - , y].room; }
} if (map [x, y + ].type == || map [x, y + ].type == ) { //south
map [x, y].type = ;
map [x, y].room = map [x, y + ].room; } if (y > ) {
if (map [x, y - ].type == || map [x, y - ].type == ) { //north
map [x, y].type = ;
map [x, y].room = map [x, y - ].room; }
}
}
}
}
通过list存储方位参数
//tile types for ease
public static List<int> roomsandfloors = new List<int> { , };
public static List<int> corners = new List<int> {,,,};
public static List<int> walls = new List<int> {,,,}; //wall direction
private static List<string> directions = new List<string> {"x","y","-y","-x"}; //,"-y"};
根据lis存储过道结构
//corners
for (int x = ; x < map_size_x -; x++) {
for (int y = ; y < map_size_y -; y++) {
if (walls.Contains (map [x, y + ].type) && walls.Contains (map [x + , y].type) && roomsandfloors.Contains (map [x + , y + ].type)) { //north
map [x, y].type = ;
map [x, y].room = map [x + , y + ].room;
}
if (y > ) {
if (walls.Contains (map [x + , y].type) && walls.Contains (map [x, y - ].type) && roomsandfloors.Contains (map [x + , y - ].type)) { //north
map [x, y].type = ;
map [x, y].room = map [x + , y - ].room; }
}
if (x > ) {
if (walls.Contains (map [x - , y].type) && walls.Contains (map [x, y + ].type) && roomsandfloors.Contains (map [x - , y + ].type)) { //north
map [x, y].type = ;
map [x, y].room = map [x - , y + ].room; }
}
if (x > && y > ) {
if (walls.Contains (map [x - , y].type) && walls.Contains (map [x, y - ].type) && roomsandfloors.Contains (map [x - , y - ].type)) { //north
map [x, y].type = ;
map [x, y].room = map [x - , y - ].room; }
}
/* door corners --- a bit problematic in this version */
if (map [x, y].type == ) {
if (map [x + , y].type == ) {
map [x, y + ].type = ;
map [x, y - ].type = ;
} else if (Dungeon.map [x - , y].type == ) {
map [x, y + ].type = ;
map [x, y - ].type = ;
}
} }
}
这样一个房间体的完整结构已经创建完毕,之后对迷宫结构生成地下城结构
for (var y = ; y < Dungeon.map_size_y; y++) {
for (var x = ; x < Dungeon.map_size_x; x++) {
int tile = Dungeon.map [x, y].type;
int orientation = Dungeon.map[x, y].orientation;
GameObject created_tile;
Vector3 tile_location;
if (!makeIt3d) {
tile_location = new Vector3 (x * tileScaling, y * tileScaling, );
} else {
tile_location = new Vector3 (x * tileScaling, , y * tileScaling);
} created_tile = null;
if (tile == ) {
GameObject floorPrefabToUse = floorPrefab;
Room room = Dungeon.map[x,y].room;
if(room != null){
foreach(CustomRoom customroom in customRooms){
if(customroom.roomId == room.room_id){
floorPrefabToUse = customroom.floorPrefab;
break;
}
}
} created_tile = GameObject.Instantiate (floorPrefabToUse, tile_location, Quaternion.identity) as GameObject;
} if ( Dungeon.walls.Contains(tile)) {
GameObject wallPrefabToUse = wallPrefab;
Room room = Dungeon.map[x,y].room;
if(room != null){
foreach(CustomRoom customroom in customRooms){
if(customroom.roomId == room.room_id){
wallPrefabToUse = customroom.wallPrefab;
break;
}
}
} created_tile = GameObject.Instantiate (wallPrefabToUse, tile_location, Quaternion.identity) as GameObject;
if(!makeIt3d){
created_tile.transform.Rotate(Vector3.forward * (- * (tile -)));
}
else{
created_tile.transform.Rotate(Vector3.up * (- * (tile -)));
}
} if (tile == ) {
if (corridorFloorPrefab)
{
created_tile = GameObject.Instantiate(corridorFloorPrefab, tile_location, Quaternion.identity) as GameObject;
}
else
{
created_tile = GameObject.Instantiate(floorPrefab, tile_location, Quaternion.identity) as GameObject;
} if (orientation == && makeIt3d)
{
created_tile.transform.Rotate(Vector3.up * (-));
} } if (Dungeon.corners.Contains(tile)) {
GameObject cornerPrefabToUse = cornerPrefab;
Room room = Dungeon.map[x,y].room;
if(room != null){
foreach(CustomRoom customroom in customRooms){
if(customroom.roomId == room.room_id){
cornerPrefabToUse = customroom.cornerPrefab;
break;
}
}
} if(cornerPrefabToUse){ //there was a bug in this line. A good man helped for fix.
created_tile = GameObject.Instantiate (cornerPrefabToUse, tile_location, Quaternion.identity) as GameObject;
if(cornerRotation){
if(!makeIt3d){
created_tile.transform.Rotate(Vector3.forward * (- * (tile -)));
}
else{
created_tile.transform.Rotate(Vector3.up * (- * (tile -)));
}
}
}
else{
created_tile = GameObject.Instantiate (wallPrefab, tile_location, Quaternion.identity) as GameObject;
}
} if (created_tile) {
created_tile.transform.parent = transform;
}
}
}
迷宫生成后,需要对房间内容进行添加,随机的物品以及房间为玩家提供游玩条件,特定的内容包含战斗条件或者任务条件
//Spawn Objects;
List<SpawnList> spawnedObjectLocations = new List<SpawnList> (); //OTHERS
for (int x = ; x < Dungeon.map_size_x; x++) {
for (int y = ; y < Dungeon.map_size_y; y++) {
if (Dungeon.map [x, y].type == &&
((Dungeon.startRoom != Dungeon.map [x, y].room && Dungeon.goalRoom != Dungeon.map [x, y].room) || maximumRoomCount <= )) {
var location = new SpawnList (); location.x = x;
location.y = y;
if (Dungeon.walls.Contains(Dungeon.map[x + , y].type)) {
location.byWall = true;
location.wallLocation = "S";
}
else if (Dungeon.walls.Contains(Dungeon.map[x - , y].type))
{
location.byWall = true;
location.wallLocation = "N";
}
else if (Dungeon.walls.Contains(Dungeon.map[x, y + ].type)) {
location.byWall = true;
location.wallLocation = "W";
}
else if (Dungeon.walls.Contains(Dungeon.map [x, y - ].type)) {
location.byWall = true;
location.wallLocation = "E";
} if (Dungeon.map [x + , y].type == || Dungeon.map [x - , y].type == || Dungeon.map [x, y + ].type == || Dungeon.map [x, y - ].type == ) {
location.byCorridor = true;
}
if (Dungeon.map [x + , y + ].type == || Dungeon.map [x - , y - ].type == || Dungeon.map [x - , y + ].type == || Dungeon.map [x + , y - ].type == ) {
location.byCorridor = true;
}
location.room = Dungeon.map[x,y].room; int roomCenterX = (int)Mathf.Floor(location.room.w / ) + location.room.x;
int roomCenterY = (int)Mathf.Floor(location.room.h / ) + location.room.y; if(x == roomCenterX + && y == roomCenterY + )
{
location.inTheMiddle = true;
}
spawnedObjectLocations.Add (location);
}
else if (Dungeon.map [x, y].type == ) {
var location = new SpawnList ();
location.x = x;
location.y = y; if (Dungeon.map [x + , y].type == ) {
location.byCorridor = true;
location.asDoor = ;
location.room = Dungeon.map[x + ,y].room; spawnedObjectLocations.Add (location);
}
else if(Dungeon.map [x - , y].type == ){
location.byCorridor = true;
location.asDoor = ;
location.room = Dungeon.map[x - ,y].room; spawnedObjectLocations.Add (location);
}
else if (Dungeon.map [x, y + ].type == ){
location.byCorridor = true;
location.asDoor = ;
location.room = Dungeon.map[x,y + ].room; spawnedObjectLocations.Add (location);
}
else if (Dungeon.map [x, y - ].type == ){
location.byCorridor = true;
location.asDoor = ;
location.room = Dungeon.map[x,y - ].room; spawnedObjectLocations.Add (location);
}
}
}
}
这样就能生成基本的随机模型
2d ver
3d ver
也可以根据需求进行修改
Unity_Dungeonize 随机生成迷宫的更多相关文章
- canvas——随机生成迷宫
先上图. 效果 代码 随机生成迷宫要求任意两点都能够找到相同的路径,也就是说,迷宫是一个连通图.随机生成迷宫可以使用普里姆算法.广度优先算法.深度优先算法等实现.这里将使用普里姆算法通过生成最小数的方 ...
- 【Javascript + Vue】实现随机生成迷宫图片
前言 成品预览:https://codesandbox.io/s/maze-vite-15-i7oik?file=/src/maze.js 不久前写了一篇文章介绍了如何解迷宫:https://www. ...
- UWP开发:自动生成迷宫&自动寻路算法(3)
+ , + ];//0<=x<=12 0<=y<=24 private static Random Rd = new Random(); 首先声明mazeMap存储数据,声明了 ...
- php生成迷宫和迷宫寻址算法实例
较之前的终于有所改善.生成迷宫的算法和寻址算法其实是一样.只是一个用了遍历一个用了递归.参考了网上的Mike Gold的算法. <?php //zairwolf z@cot8.com heade ...
- PHP树生成迷宫及A*自己主动寻路算法
PHP树生成迷宫及A*自己主动寻路算法 迷宫算法是採用树的深度遍历原理.这样生成的迷宫相当的细,并且死胡同数量相对较少! 随意两点之间都存在唯一的一条通路. 至于A*寻路算法是最大众化的一全自己主动寻 ...
- Prim算法生成迷宫
初始化地图 function initMaze(r,c){ let row = new Array(2 * r + 1) for(let i = 0; i < row.length; i++){ ...
- 随机生成长度为len的密码,且包括大写、小写英文字母和数字
一道华三面试题,随机生成长度为len的密码,且包括大写.小写英文字母和数字,主要Random类的使用,random.nextInt(len)表示生成[0,len)整数.具体实现见下面代码,已经很详细了 ...
- Java随机生成18位身份证号
package com.ihome.data; import java.text.SimpleDateFormat; import java.util.Calendar; import java.ut ...
- js 随机生成姓名、手机号、身份证号、银行卡号
开发测试的时候,经常需要填写姓名.手机号.身份证号.银行卡号,既要符合格式要求.又不能重复.大家会到网上搜各种生成器.能不能自己写一个简单的生成器呢.下面是随机生成姓名.手机号.身份证号.银行卡号的j ...
随机推荐
- 怎么让FOXMAIL关了以后在右下角自动收取邮件
1.缩小到任务栏:打开foxmail,在工具-系统设置-常规,选项中有一项最小化时在任务栏显示,勾选上即可.2.要自动收取邮件,选中邮件账户,右键打开菜单,属性-接收邮件,右边勾选上“每隔*分钟自动收 ...
- Mysql怎样控制replace替换的次数?
我想把“ABC是ABC”替换成“123是ABC”,也就是找出第一个ABC替换成123,MYSQL命令应该怎么写? UPDATE data SET body=REPLACE(body, 'ABC', ' ...
- Notice: Use of undefined constant - assumed ' '
昨天看手册的时候有两个范例,懒得写了,直接复制,测试一下,结果报Notice; 反复检查无果,最后, 手动敲了一遍,居然正常了,汗.... 总结:偷懒害人
- .gitkeep常用写法
# win & OSX system files .DS_Store Thumbs.db ehthumbs.db Desktop.ini # IDE files .idea # project ...
- 2019-9-22-dotnet-core-导出-COM-组件
title author date CreateTime categories dotnet core 导出 COM 组件 lindexi 2019-09-22 20:25:38 +0800 2019 ...
- vue-learning:41 - Vuex - 第二篇:const store = new Vue.Store(option)中option选项、store实例对象的属性和方法
vuex 第二篇:const store = new Vue.Store(option)中option选项.store实例对象的属性和方法 import Vuex from 'vuex' const ...
- Linux 内核 EISA 总线
扩展 ISA (EISA) 总线是一个对 ISA 的 32-位 扩展, 带有一个兼容的接口连接器; ISA 设备板可被插入一个 EISA 连接器. 增加的线在 ISA 接触之下被连接. 如同 PCI ...
- MYSQL 查询日期最大的那条记录
首先把官网示例拿出来: 连接查询比子查询性能更好 3.6.4 The Rows Holding the Group-wise Maximum of a Certain Column Task: For ...
- IDE介绍之——CLion
CLion是JetBrains公司旗下发布的一款跨平台C/C++IDE开发工具. 使用CLion上最好要会手写CMake.要先安装编译器套件(一般安装MinGW就行). 对C++标准的支持:基本上Cl ...
- Angular 利用 marked.js 添加 Markdown + HTML 同时渲染的 Pipe
背景 最近在公司开发的一个项目需要在 Angular 上展示图文,并且需要同时支持 Markdown 和 HTML 对于同时支持 Markdown 和 HTML ,应该要分为编辑和渲染两部分考虑. 对 ...