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

}
运行效果图:
最开始随机出来的地图,后面是逐步处理的效果:



posted @ 2018-04-14 19:03  sufferingStriver  阅读(8049)  评论(0编辑  收藏  举报