BSP地牢生成不会生成走廊



我正在为我的毕业项目制作一个 2D RPG,我正处于想要随机生成地牢的地步。
我正在按照本教程 http://www.rombdn.com/blog/2018/01/12/random-dungeon-bsp-unity/制作一个随机生成的地牢。

经过大量的研究,我发现BSP算法为我的游戏生成了我想要的地下城设计。我已经按照链接中提供的教程逐步操作。我提供了我的脚本供您查看:

public class BoardManager : MonoBehaviour {
    public GameObject floorTile;
    public GameObject corridorTile;
public int boardRows, boardColumns;
public int minRoomSize, maxRoomSize;
private GameObject[,] boardPositionsFloor;
public class SubDungeon {
    public SubDungeon left, right;
    public Rect rect;
    public Rect room = new Rect(-1,-1, 0, 0); // i.e null
    public int debugId;
    private static int debugCounter = 0;
    public List<Rect> corridors = new List<Rect>();
    public SubDungeon(Rect mrect) {
        rect = mrect;
        debugId = debugCounter;
        debugCounter++;
    }
    public bool IAmLeaf() {
        return left == null && right == null;
    }
    public bool Split(int minRoomSize, int maxRoomSize) {
        if (!IAmLeaf()) {
            return false;
        }
        // choose a vertical or horizontal split depending on the proportions
        // i.e. if too wide split vertically, or too long horizontally,
        // or if nearly square choose vertical or horizontal at random
        bool splitH;
        if (rect.width / rect.height >= 1.25) {
            splitH = false;
        } else if (rect.height / rect.width >= 1.25) {
            splitH = true;
        } else {
            splitH = Random.Range (0.0f, 1.0f) > 0.5;
        }
        if (Mathf.Min(rect.height, rect.width) / 2 < minRoomSize) {
            Debug.Log ("Sub-dungeon " + debugId + " will be a leaf");
            return false;
        }
        if (splitH) {
            // split so that the resulting sub-dungeons widths are not too small
            // (since we are splitting horizontally)
            int split = Random.Range (minRoomSize, (int)(rect.width - minRoomSize));
            left = new SubDungeon (new Rect (rect.x, rect.y, rect.width, split));
            right = new SubDungeon (
                new Rect (rect.x, rect.y + split, rect.width, rect.height - split));
        }
        else {
            int split = Random.Range (minRoomSize, (int)(rect.height - minRoomSize));
            left = new SubDungeon (new Rect (rect.x, rect.y, split, rect.height));
            right = new SubDungeon (
                new Rect (rect.x + split, rect.y, rect.width - split, rect.height));
        }
        return true;
    }
    public void CreateRoom() {
        if (left != null) {
            left.CreateRoom ();
        }
        if (right != null) {
            right.CreateRoom ();
        }
        if (IAmLeaf()) {
            int roomWidth = (int)Random.Range (rect.width / 2, rect.width - 2);
            int roomHeight = (int)Random.Range (rect.height / 2, rect.height - 2);
            int roomX = (int)Random.Range (1, rect.width - roomWidth - 1);
            int roomY = (int)Random.Range (1, rect.height - roomHeight - 1);
            // room position will be absolute in the board, not relative to the sub-dungeon
            room = new Rect (rect.x + roomX, rect.y + roomY, roomWidth, roomHeight);
            Debug.Log ("Created room " + room + " in sub-dungeon " + debugId + " " + rect);
        }
    }
    public Rect GetRoom() {
        if (IAmLeaf()) {
            return room;
        }
        if (left != null) {
            Rect lroom = left.GetRoom ();
            if (lroom.x != -1) {
                return lroom;
            }
        }
        if (right != null) {
            Rect rroom = right.GetRoom ();
            if (rroom.x != -1) {
                return rroom;
            }
        }
        // workaround non nullable structs
        return new Rect (-1, -1, 0, 0);
    }
    public void CreateCorridorBetween(SubDungeon left, SubDungeon right) {
        Rect lroom = left.GetRoom ();
        Rect rroom = right.GetRoom ();
        Debug.Log("Creating corridor(s) between " + left.debugId + "(" + lroom + ") and " + right.debugId + " (" + rroom + ")");
        Debug.Log ("hello");
        // attach the corridor to a random point in each room
        Vector2 lpoint = new Vector2 ((int)Random.Range (lroom.x + 1, lroom.xMax - 1), (int)Random.Range (lroom.y + 1, lroom.yMax - 1));
        Vector2 rpoint = new Vector2 ((int)Random.Range (rroom.x + 1, rroom.xMax - 1), (int)Random.Range (rroom.y + 1, rroom.yMax - 1));
        // always be sure that left point is on the left to simplify the code
        if (lpoint.x > rpoint.x) {
            Vector2 temp = lpoint;
            lpoint = rpoint;
            rpoint = temp;
        }
        int w = (int)(lpoint.x - rpoint.x);
        int h = (int)(lpoint.y - rpoint.y);
        Debug.Log ("lpoint: " + lpoint + ", rpoint: " + rpoint + ", w: " + w + ", h: " + h);
        // if the points are not aligned horizontally
        if (w != 0) {
            // choose at random to go horizontal then vertical or the opposite
            if (Random.Range (0, 1) > 2) {
                // add a corridor to the right
                corridors.Add (new Rect (lpoint.x, lpoint.y, Mathf.Abs (w) + 1, 1));
                // if left point is below right point go up
                // otherwise go down
                if (h < 0) {
                    corridors.Add (new Rect (rpoint.x, lpoint.y, 1, Mathf.Abs (h)));
                } else {
                    corridors.Add (new Rect (rpoint.x, lpoint.y, 1, -Mathf.Abs (h)));
                }
            } else {
                // go up or down
                if (h < 0) {
                    corridors.Add (new Rect (lpoint.x, lpoint.y, 1, Mathf.Abs (h)));
                } else {
                    corridors.Add (new Rect (lpoint.x, rpoint.y, 1, Mathf.Abs (h)));
                }
                // then go right
                corridors.Add (new Rect (lpoint.x, rpoint.y, Mathf.Abs (w) + 1, 1));
            }
        } else {
            // if the points are aligned horizontally
            // go up or down depending on the positions
            if (h < 0) {
                corridors.Add (new Rect ((int)lpoint.x, (int)lpoint.y, 1, Mathf.Abs (h)));
            } else {
                corridors.Add (new Rect ((int)rpoint.x, (int)rpoint.y, 1, Mathf.Abs (h)));
            }
        }
        Debug.Log ("Corridors: ");
        foreach (Rect corridor in corridors) {
            Debug.Log ("corridor: " + corridor);
        }
    }
}
public void CreateBSP(SubDungeon subDungeon) {
    Debug.Log ("Splitting sub-dungeon " + subDungeon.debugId + ": " + subDungeon.rect);
    if (subDungeon.IAmLeaf()) {
        // if the sub-dungeon is too large
        if (subDungeon.rect.width > maxRoomSize
            || subDungeon.rect.height > maxRoomSize
            || Random.Range(0.0f,1.0f) > 0.25) {
            if (subDungeon.Split (minRoomSize, maxRoomSize)) {
                Debug.Log ("Splitted sub-dungeon " + subDungeon.debugId + " in "
                    + subDungeon.left.debugId + ": " + subDungeon.left.rect + ", "
                    + subDungeon.right.debugId + ": " + subDungeon.right.rect);
                CreateBSP(subDungeon.left);
                CreateBSP(subDungeon.right);
            }
        }
    }
}
public void DrawRooms(SubDungeon subDungeon) {
    if (subDungeon == null) {
        return;
    }
    if (subDungeon.IAmLeaf()) {
        for (int i = (int)subDungeon.room.x; i < subDungeon.room.xMax; i++) {
            for (int j = (int)subDungeon.room.y; j < subDungeon.room.yMax; j++) {
                GameObject instance = Instantiate (floorTile, new Vector3 (i, j, 0f), Quaternion.identity) as GameObject;
                instance.transform.SetParent (transform);
                boardPositionsFloor [i, j] = instance;
            }
        }
    } else {
        DrawRooms (subDungeon.left);
        DrawRooms (subDungeon.right);
    }
}
void DrawCorridors(SubDungeon subDungeon) {
    if (subDungeon == null) {
        return;
    }
    DrawCorridors (subDungeon.left);
    DrawCorridors (subDungeon.right);
    foreach (Rect corridor in subDungeon.corridors) {
        for (int i = (int)corridor.x; i < corridor.xMax; i++) {
            for (int j = (int)corridor.y; j < corridor.yMax; j++) {
                if (boardPositionsFloor [i, j] == null) {
                    GameObject instance = Instantiate (corridorTile, new Vector3 (i, j, 0f), Quaternion.identity) as GameObject;
                    instance.transform.SetParent (transform);
                    boardPositionsFloor [i, j] = instance;
                }
            }
        }
    }
}
void Start () {
    SubDungeon rootSubDungeon = new SubDungeon (new Rect (0, 0, boardRows, boardColumns));
    CreateBSP (rootSubDungeon);
    rootSubDungeon.CreateRoom ();
    boardPositionsFloor = new GameObject[boardRows, boardColumns];
    DrawCorridors (rootSubDungeon);
    DrawRooms (rootSubDungeon);
}
}

房间正在完美地创建,没有错误消息。我注意到 CreateCorridorBetween 没有从任何地方调用,即使在作者的博客上也是如此;因此,不会创建廊道。如何在代码中调用它?

考虑到CreateCorridorBetween的参数SubDungeon leftSubDungeon right您希望在创建房间后调用该方法。我假设您已经阅读了您链接到的博客,但正如作者所说

连接房间:在房间之间创建走廊

隔离房间不是很有用,因此我们将在它们之间添加走廊。为此,我们将每个叶子连接到其同级。然后在树中向上一层,我们将重复连接父子地下城的过程,直到最后我们连接两个初始子地下城(参见堆栈交换答案以获取插图(。

这意味着这比基本的"只是称之为"解决方案还有更多。

希望这对您的项目有所帮助并祝您好运!

相关内容

  • 没有找到相关文章

最新更新