引言
本人作為一個游戲愛好者,入坑unity引擎半年。作為一個小白,在假期的時候嘗試寫一下 rouguelike游戲,但在一開始的圖算法的時候就遇到了瓶頸,花了很長的時間去摸索,因為國內(nèi)對于地圖算法程序的博客比較難找,翻閱很多國外網(wǎng)站(用翻譯軟件),自己寫了一個小算法。希望能幫到一些熱愛roguelike游戲的新手開發(fā)者。
(在最近的時間本人玩了很多的Roguelike游戲:以撒的結(jié)合,地牢之魂等等,我們就以它們?yōu)閰⒖迹?/p>
?
在寫算法的時候我們要想到如何使它快速的應(yīng)用于游戲引擎,所以這里我把地圖的每種元素以坐標(數(shù)組來表示坐標)對應(yīng)起來。在Unity中吧相應(yīng)的GameObject對應(yīng)地圖元素的坐標,就可以直接生成一個roguelike3d的地牢場景。
在這些地牢游戲中,他們每一層都有一個角色最初所在房間(初始房間)所以這里我們先定個小小目標創(chuàng)建初始房間。我們以一個簡單的例子,以撒的結(jié)合偽隨機地圖來說。(原作肯定不是我這種創(chuàng)建方法,但主要是一個地牢創(chuàng)建的思想)這里算法我用C#來給大家舉例。
?
方法步驟
第一步,初始化地圖:第一步主要是創(chuàng)建一個一定空間大小的房間。在程序中我們通過創(chuàng)建二維數(shù)組來定義這個房間。同時我們需要創(chuàng)建一個枚舉來表示房間中的不同元素,例如#表示地面,由于#是一個符號類型,所以我們將數(shù)組用char 來創(chuàng)建:char[,] map;,此時就可以在對應(yīng)坐標存放相應(yīng)的元素了。
第二步,創(chuàng)建第一個房間,加入房間類組的List。(list用于存放已經(jīng)生成的房間,用于在選擇一個房間這一步進行隨機選擇)
第三步,從list中選擇一個房間(準備以該房間為標準,選擇它四個方向其一,沿著此方向創(chuàng)建新的元素)
第四步,選擇一個方向,遍歷方向?qū)?yīng)的空間是否足夠放下一個房間;如果能繼續(xù),如果不能返回第三步。
第五步,創(chuàng)建新的房間。
第六步,選擇創(chuàng)建房間的個數(shù)循環(huán)創(chuàng)建房間直到地牢完成
大家根據(jù)自身需要來添加自己需要的步驟和需要創(chuàng)建的元素這里放我完成的一個簡單的偽隨機地牢圖以及代碼例如
選擇特定房間加入元素npc等。。
這里放一張運行結(jié)果圖
下面是代碼
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Room { public int x_H_Length; public int y_H_Length; public int x_Point; public int y_Point; public string roomStyle; } public class NormalRoom : Room { public NormalRoom() { x_H_Length = y_H_Length = 4; roomStyle = "NormalRoom"; } } //可以自己創(chuàng)建需要的房間類如:商店 boss房等,這里我只用到普通房間為例子 class Dungeon { //存儲房間的數(shù)組 List roomList = new List(); int roomListLength = 0; //定義地牢的整體大小 int sizex, sizey; char[,] map; //定義生成地圖種子 public int seed; //創(chuàng)建地圖元素的枚舉這里只用到了地板和門:#和D根據(jù)需要來創(chuàng)建這些枚舉 int doorTempx, doorTempy, areaTempx, areaTempy; enum Mark { floor = '#', door = 'D', monster = 'm', chests = 'c' } //ran用來隨機 Random ran; void InitializeDungeon(int sizex,int sizey) { this.sizex = sizex; this.sizey = sizey; map = new char[sizex, sizey]; } //創(chuàng)建房間的方法,下面通過CreateFirstRoom和CreateNextRoom將它調(diào)用 void GenerateRoom(Room Rm) { for (int i =Rm.x_Point - Rm.x_H_Length; i <= Rm.x_Point + Rm.x_H_Length; i++) { for (int j = Rm.y_Point - Rm.y_H_Length; j <= Rm.y_Point + Rm.y_H_Length; j++) { map[i, j] = (char)Mark.floor; } } roomList.Add(Rm); roomListLength++; } //創(chuàng)建第一個房間 void CreateFirstRoom() { NormalRoom firstR = new NormalRoom(); //在中心位置創(chuàng)建出初始房間 firstR.x_Point = sizex / 2; firstR.y_Point = sizey / 2; GenerateRoom(firstR); } //上文提到的CreateNextRoom方法:用于在第一個房間創(chuàng)建完成后繼續(xù)創(chuàng)建房間。 void CreateNextRoom() { int roomNum; int wallPos; bool CDtemp = true; while (CDtemp) { ran = new Random(seed); roomNum = ran.Next(roomListLength); wallPos = ran.Next(4); seed = ran.Next(); Room m = roomList[roomNum]; ChoiceNextArea(m, wallPos); if (ChoiceNextArea(m, wallPos)) { CDtemp = false; } } map[doorTempx, doorTempy] = (char)Mark.door; Room CNRRoom = new NormalRoom(); CNRRoom.x_Point = areaTempx; CNRRoom.y_Point = areaTempy; int p = CNRRoom.x_Point; int n = CNRRoom.y_Point; //表示生成房間的每個房間的中心點,輸出在控制臺可查看 Console.WriteLine(p + " " + n); GenerateRoom(CNRRoom); } //該方法用于選擇所選定房間的方向 private bool ChoiceNextArea(Room Room,int Pos) { bool CDtemp = false; switch (Pos) { case 0: if (Room.x_Point + 3*Room.x_H_Length + 2 < sizex && map[Room.x_Point + 2 * Room.x_H_Length + 2,Room.y_Point] != '#') { //下方的步驟是為了標記所選方向準備創(chuàng)建的房間中心以及連接兩房間門的標記 doorTempx = Room.x_Point + Room.x_H_Length + 1; doorTempy = Room.y_Point areaTempx = Room.x_Point + 2*Room.x_H_Length + 2; areaTempy = Room.y_Point; CDtemp = true; }; break; case 1: if (Room.y_Point + 3*Room.y_H_Length + 2 0 && map[Room.x_Point - 2 * Room.x_H_Length - 1, Room.y_Point] != '#') { doorTempx = Room.x_Point - Room.x_H_Length - 1; doorTempy = Room.y_Point; areaTempx = Room.x_Point - 2 * Room.x_H_Length - 2; areaTempy = Room.y_Point; CDtemp = true; }; break; case 3: if (Room.y_Point - 3*Room.y_H_Length - 1 > 0 && map[Room.x_Point ,Room.y_Point - 2 * Room.y_H_Length - 1] != '#') { doorTempx = Room.x_Point; doorTempy = Room.y_Point - Room.y_H_Length - 1; areaTempx = Room.x_Point; areaTempy = Room.y_Point - 2 * Room.y_H_Length - 2; CDtemp = true; }; break; } return CDtemp; } public static void FinishDungeon() { Dungeon level = new Dungeon(); //seed為生成地圖種子的值可以根據(jù)你的需求來定它的大小 level.seed = 8; //初始化迷宮 level.InitializeDungeon(100, 100); //創(chuàng)建第一個房間 level.CreateFirstRoom(); //p為房間數(shù)目,循環(huán)創(chuàng)建10個1房間 for(int p = 0; p < 10; p++) { level.CreateNextRoom(); } //輸出整個地圖到控制臺,檢查生成的地圖 for(int i = 0; i < level.sizex; i++) { for(int j = 0; j < level.sizey; j++) { Console.Write(level.map[i, j]); } Console.WriteLine(); } Console.WriteLine(level.roomList[0].ToString()); } } class Program { static void Main(string[] args) { Dungeon.FinishDungeon(); } } }
實現(xiàn)之后可以得到每個坐標以及對應(yīng)的元素,在unity中生成對應(yīng)坐標的預(yù)設(shè)物體就就做好了一個Roguelike
程序的實現(xiàn)很簡單,由于本人只是新手所以寫的不是很好,請大家見諒!
- 還沒有人評論,歡迎說說您的想法!