roguelike地圖的隨機生成算法


如果要想自己設計一個roguelike游戲,那么需要你有一個隨機地圖生成,我在indienova上看到一篇文章,描述了一個roguelike算法,然后自己用unity實現了一個下。

原文地址:隨機生成 Tile Based 地圖之——洞穴

原文有這個算法的各種講解,還有動態的演示圖,不理解算法原理的可以去看一下。

根據這個算法的代碼:

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 ();
    }

}
運行效果圖:
最開始隨機出來的地圖,后面是逐步處理的效果:




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM