Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / generate / GenerateDungeon.cs
@小李xl 小李xl on 30 Dec 2022 3 KB 随机地牢生成

using System.Collections.Generic;
using Godot;

/// <summary>
/// 地牢生成器
/// </summary>
public class GenerateDungeon
{
    public readonly TileMap TileMap;

    private Grid<bool> _roomGrid = new Grid<bool>();
    private List<RoomInfo> _roomInfos = new List<RoomInfo>();
    private int _count = 0;
    private int _maxCount = 30;

    public GenerateDungeon(TileMap tileMap)
    {
        TileMap = tileMap;
    }

    public void Generate()
    {
        GenerateRoom(null, 0);

        foreach (var info in _roomInfos)
        {
            //临时铺上地砖
            var id = (int)TileMap.TileSet.GetTilesIds()[0];
            for (int i = 0; i < info.Size.x; i++)
            {
                for (int j = 0; j < info.Size.y; j++)
                {
                    TileMap.SetCell(i + (int)info.Position.x, j + (int)info.Position.y, id);
                }
            }
        }
    }

    private RoomInfo GenerateRoom(RoomInfo prevRoomInfo, int direction)
    {
        if (_count > _maxCount)
        {
            return null;
        }
        _count++;
        var info = new RoomInfo();
        info.Size = new Vector2(Utils.RandRangeInt(10, 30), Utils.RandRangeInt(10, 30));
        info.Position = Vector2.Zero;
        info.Direction = direction;

        if (prevRoomInfo != null) //表示这不是第一个房间, 就得判断当前位置下的房间是否被遮挡
        {
            //房间间隔
            var space = Utils.RandRangeInt(3, 4);
            //中心偏移
            int offset;
            if (direction == 0 || direction == 2)
            {
                offset = Utils.RandRangeInt(-(int)prevRoomInfo.Size.y, (int)prevRoomInfo.Size.y);
            }
            else
            {
                offset = Utils.RandRangeInt(-(int)prevRoomInfo.Size.x, (int)prevRoomInfo.Size.x);
            }
            //计算房间位置
            if (direction == 0) //上
            {
                info.Position = new Vector2(prevRoomInfo.Position.x + offset,
                    prevRoomInfo.Position.y - info.Size.y - space);
            }
            else if (direction == 1) //右
            {
                info.Position = new Vector2(prevRoomInfo.Position.x + prevRoomInfo.Size.y + space, prevRoomInfo.Position.y + offset);
            }
            else if (direction == 2) //下
            {
                info.Position = new Vector2(prevRoomInfo.Position.x + offset, prevRoomInfo.Position.y + prevRoomInfo.Size.y + space);
            }
            else if (direction == 3) //左
            {
                info.Position = new Vector2(prevRoomInfo.Position.x - info.Size.x - space,
                    prevRoomInfo.Position.y + offset);
            }
            
            //是否碰到其他房间
            if (_roomGrid.RectCollision(info.Position - new Vector2(1, 1), info.Size + new Vector2(2, 2)))
            {
                return null;
            }
        }
        
        _roomInfos.Add(info);
        _roomGrid.AddRect(info.Position, info.Size, true);
        
        //下一个房间
        //0上, 1右, 2下, 3左
        var dirList = new List<int>(new []{ 0, 1, 2, 3 });
        if (prevRoomInfo != null)
        {
            dirList.Remove(GetReverseDirection(direction));
        }

        while (dirList.Count > 0)
        {
            var randDir = Utils.RandChoose(dirList);
            var generateRoom = GenerateRoom(info, randDir);
            if (generateRoom == null)
            {
                break;
            }

            dirList.Remove(randDir);
        }
        
        
        return info;
    }

    private int GetReverseDirection(int direction)
    {
        switch (direction)
        {
            case 0: return 2;
            case 1: return 3;
            case 2: return 0;
            case 3: return 1;
        }

        return 2;
    }
}