如果要想自己設計一個roguelike游戲,那么需要你有一個隨機地圖生成,我在indienova上看到一篇文章,描述了一個roguelike算法,然后自己用unity實現了一個下。
原文有這個算法的各種講解,還有動態的演示圖,不理解算法原理的可以去看一下。
根據這個算法的代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Tile
{
Floor,//地板
Wall//牆
}
public class createMap : MonoBehaviour {
public int row = 30;
public int col = 30;
private Tile[,] mapArray;
public GameObject wall, floor,player;
private GameObject map;
private Transform maps;
private int forTimes=0;//SmoothMapArray循環次數
// Use this for initialization
void Start () {
mapArray = new Tile[row,col];
maps = GameObject.FindGameObjectWithTag ("map").transform;
map = new GameObject ();
map.transform.SetParent (maps);
//CreateMap ();
GenerateMap ();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.Q)) {
Destroy (map);
GenerateMap ();
}
if (Input.GetKeyDown (KeyCode.W)) {
InitMap ();
}
//下一步
if (Input.GetKeyDown (KeyCode.E)) {
CreateMap ();
}
}
private void InitMapArray(){
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
//采用<50%生成牆
mapArray[i,j] = Random.Range(0,100)<40?Tile.Wall:Tile.Floor;
//邊界置為牆
if (i == 0 || j == 0 || i == row - 1 || j == col - 1) {
mapArray [i, j] = Tile.Wall;
}
}
}
}
private Tile[,] SmoothMapArray0(){
Tile[,] newMapArray = new Tile[row,col];
int wallCount1 = 0,wallCount2 = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
wallCount1 = CheckNeighborWalls (mapArray, i, j, 1);
wallCount2 = CheckNeighborWalls (mapArray, i, j, 2);
if (mapArray [i, j] == Tile.Wall) {
newMapArray [i, j] = (wallCount1 >= 4) ? Tile.Wall : Tile.Floor;
} else {
newMapArray [i, j] = (wallCount1 >= 5 || wallCount2<=2) ? Tile.Wall : Tile.Floor;
}
if (i == 0 || i == row - 1 || j == 0 || j == col - 1) {
newMapArray [i, j] = Tile.Wall;
}
}
}
return newMapArray;
}
//4-5規則
//當前牆:周圍超過4個保持為牆
//當前地板:周圍超過5個牆變為牆
//循環4-5次
private Tile[,] SmoothMapArray1(){
Tile[,] newMapArray = new Tile[row,col];
int wallCount = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
wallCount = CheckNeighborWalls (mapArray, i, j, 1);
if (mapArray [i, j] == Tile.Wall) {
newMapArray [i, j] = (wallCount >= 4) ? Tile.Wall : Tile.Floor;
} else {
newMapArray [i, j] = (wallCount >= 5) ? Tile.Wall : Tile.Floor;
}
if (i == 0 || i == row - 1 || j == 0 || j == col - 1) {
newMapArray [i, j] = Tile.Wall;
}
}
}
return newMapArray;
}
//判斷周圍牆的數量
private int CheckNeighborWalls(Tile[,] mapArray, int i,int j,int t){
int count = 0;
for (int k = i - t; k <= i + t; k++) {
for (int l = j - t; l <= j + t; l++) {
if (k >= 0 && k < row && l >= 0 && l < col) {
if (mapArray[k,l] == Tile.Wall) {
count++;
}
}
}
}
//去除本身是否為牆
if (mapArray[i,j] == Tile.Wall) {
count--;
}
return count;
}
private void InstanceMap (){
bool setPlayer = true;
map = new GameObject ();
map.transform.SetParent (maps);
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (mapArray [i, j] == Tile.Floor) {
GameObject go = Instantiate (floor, new Vector3 (i, j, 1), Quaternion.identity) as GameObject;
go.transform.SetParent (map.transform);
//設置層級
go.layer = LayerMask.NameToLayer ("floor");
if (setPlayer) {
//設置角色
GameObject g_player = Instantiate (player, new Vector3 (i, j, 1), Quaternion.identity) as GameObject;
g_player.transform.SetParent (map.transform);
setPlayer = false;
}
} else if (mapArray [i, j] == Tile.Wall) {
GameObject go = Instantiate (wall, new Vector3 (i, j, 1), Quaternion.identity) as GameObject;
go.transform.SetParent (map.transform);
go.layer = LayerMask.NameToLayer ("wall");
}
}
}
}
private void InitMap (){
forTimes = 0;
Destroy (map);
map = new GameObject ();
map.transform.SetParent (maps);
InitMapArray ();
InstanceMap ();
}
private void CreateMap (){
Destroy (map);
map = new GameObject ();
map.transform.SetParent (maps);
if (forTimes < 7) {
if (forTimes < 4) {
mapArray = SmoothMapArray0 ();
} else {
mapArray = SmoothMapArray1 ();
}
forTimes++;
}
InstanceMap ();
}
private void GenerateMap (){
forTimes = 0;
map = new GameObject ();
map.transform.SetParent (maps);
InitMapArray ();
while (forTimes < 7) {
if (forTimes < 4) {
mapArray = SmoothMapArray0 ();
} else {
mapArray = SmoothMapArray1 ();
}
forTimes++;
}
InstanceMap ();
}
}
運行效果圖:
最開始隨機出來的地圖,后面是逐步處理的效果:





