[Unity]Roguelike随机地图生成(一)

10 篇文章 0 订阅

初步随机地图生成

基础房间生成

首先需要确定每次房间生成都是在上一个房间的哪个方向上生成,为此需要声明一个枚举值来记录上下左右四个方向
创建脚本RoomGenerator,声明方向枚举值

	/// <summary>
    /// 方向
    /// </summary>
    public enum Direction
    {
        LEFT = 0,
        RIGHT = 1,
        TOP = 2,
        BOTTOM = 3
    }

    //下次生成房间的方向
    private Direction direction;

此外我们还需要声明以下几个变量

  • 基础房间的GameObject变量
  • 房间最大数量
  • 当前已生成的所有房间列表
  • 房间生成点
  • X,Y轴的位置偏移量
  • 起始和结束房间
	//基础房间预制体
    public GameObject baseRoom;
    //房间最大个数
    public int maxCreateNum;
    //当前房间列表
    private List<Room> roomList = new List<Room>();
    //生成点
    public Transform spawnPoint;
    //生成点偏移量
    public float xOffset, yOffset;

	public GameObject startRoom;
    public GameObject endRoom;

转到unity,使用一个Square来暂时充当基础房间
在这里插入图片描述
将该sprite拖为预制体,并创建一个Room脚本,拖拽到此预制体上
在这里插入图片描述

设置一个房间层级Room
在这里插入图片描述

接下来使用随机数来确定下一次生成房间的方向

	/// <summary>
    /// 随机创建房间方向
    /// </summary>
    void RandomDirection()
    {
    	direction = (Direction) Random.Range(0, 4);

        switch (direction)
        {
            case Direction.LEFT:
                spawnPoint.position += new Vector3(-xOffset, 0, 0);
                break;
            case Direction.RIGHT:
                spawnPoint.position += new Vector3(xOffset, 0, 0);
                break;
            case Direction.BOTTOM:
                spawnPoint.position += new Vector3(0, -yOffset, 0);
                break;
            case Direction.TOP:
                spawnPoint.position += new Vector3(0, yOffset, 0);
                break;
            }
    }

创建房间

	void Start()
    {
        CreateRoom();
    }
	
	/// <summary>
    /// 创建随机地图
    /// </summary>
    void CreateRoom()
    {
        for (int i = 0; i < maxCreateNum; i++)
        {
            CreateRoomObj(baseRoom, spawnPoint.position);
            RandomDirection();
        }
    }

    /// <summary>
    /// 创建房间
    /// </summary>
    /// <param name="room">房间预制体对象</param>
    /// <param name="pos">位置</param>
    void CreateRoomObj(GameObject room, Vector3 pos)
    {
        GameObject obj = Instantiate(room, pos, Quaternion.identity);
        roomList.Add(obj.GetComponent<Room>());
    }

转到unity,新建一个Gameobject,命名为RoomGenerator,并在此对象下新建一个子对象SpawnRoomPoint
在这里插入图片描述
在RoomGenerator上挂载脚本RoomGenerator.cs,设置基础房间和房间生成点,X和Y轴的偏移量根据自己需要去设置
在这里插入图片描述
到此已经可以随机生成地图,但是生成的房间有可能会重叠
在这里插入图片描述

因此我们需要在移动房间生成点时进行判断,判断当前位置是否已经有一个房间

首先在BaseRoom预制体上添加一个BoxCollider2D来做占位检测
在这里插入图片描述
修改随机方向函数,声明一个检测半径变量

    //检测半径(当前位置是否有一个房间)
    public float roomColliderRadius;

使用Physics2D.OverlapCircle函数来检测当前位置是否有房间,该方法返回一个检测到的Collider2D,如果没有则返回null

void RandomDirection()
    {
        do
        {
            direction = (Direction) Random.Range(0, 4);

            switch (direction)
            {
                case Direction.LEFT:
                    spawnPoint.position += new Vector3(-xOffset, 0, 0);
                    break;
                case Direction.RIGHT:
                    spawnPoint.position += new Vector3(xOffset, 0, 0);
                    break;
                case Direction.BOTTOM:
                    spawnPoint.position += new Vector3(0, -yOffset, 0);
                    break;
                case Direction.TOP:
                    spawnPoint.position += new Vector3(0, yOffset, 0);
                    break;
            }

        } while (Physics2D.OverlapCircle(spawnPoint.position, roomColliderRadius, roomLayer));
    }

再次运行房间就不会再重叠在一起
在这里插入图片描述
接下来我们需要制作房间四个方向的门的判断

房间门的判断

首先我们需要声明以下几种变量

  • 四个方向门的GameObject对象
  • 四个bool值来判断该房间当前有哪几个方向是会出现门
  • 总的门数量
	//四个门
    public GameObject doorLeft, doorRight, doorTop, doorBottom;
    
    public bool isLeft;
    public bool isRight;
    public bool isTop;
    public bool isBottom;

在BaseRoom预制体下创建四个子对象,并重新命名为对应的方向枚举值,例如右边的门就是1,左边就是0
在这里插入图片描述
注意上面门的命名要根据方向枚举值来设置,要一一对应

	public enum Direction
    {
        LEFT = 0,
        RIGHT = 1,
        TOP = 2,
        BOTTOM = 3
    }

在Room脚本里来初始化四个门的实例对象

	void Awake()
    {
        foreach (Transform door in transform)
        {
            switch ((RoomGenerator.Direction)Convert.ToInt32(door.gameObject.name))
            {
                case RoomGenerator.Direction.LEFT:
                    doorLeft = door.gameObject;
                    break;
                case RoomGenerator.Direction.RIGHT:
                    doorRight = door.gameObject;
                    break;
                case RoomGenerator.Direction.TOP:
                    doorTop = door.gameObject;
                    break;
                case RoomGenerator.Direction.BOTTOM:
                    doorBottom = door.gameObject;
                    break;
            }   
        }
    }

根据四个方向门的状态来确定需要开启哪几扇门

	void Start()
    {
        doorLeft.SetActive(isLeft);
        doorRight.SetActive(isRight);
        doorBottom.SetActive(isBottom);
        doorTop.SetActive(isTop);
    }

更新门的总数

	public void UpdateRoomState()
    {
        if (isLeft) doorNumber++;
        if (isRight) doorNumber++;
        if (isTop) doorNumber++;
        if (isBottom) doorNumber++;
    }

转到RoomGenerator脚本,同样使用Physics2D.OverlapCircle来判断四周是否有相邻的房间

	/// <summary>
    /// 检测当前房间周围的房间数量
    /// </summary>
    /// <param name="room"></param>
    /// <param name="pos"></param>
    void CheckRoomDoor(Room room, Vector3 pos)
    {
        Collider2D left = Physics2D.OverlapCircle(pos + new Vector3(-xOffset, 0, 0), roomColliderRadius, roomLayer);
        Collider2D right = Physics2D.OverlapCircle(pos + new Vector3(xOffset, 0, 0), roomColliderRadius, roomLayer);
        Collider2D top = Physics2D.OverlapCircle(pos + new Vector3(0, yOffset, 0), roomColliderRadius, roomLayer);
        Collider2D bottom = Physics2D.OverlapCircle(pos + new Vector3(0, -yOffset, 0), roomColliderRadius, roomLayer);

        room.isLeft = left;
        room.isRight = right;
        room.isTop = top;
        room.isBottom = bottom;

        room.UpdateRoomState();
    }

在创建完房间后调用上面的方法来开启房间对应方向的门

	void Start()
    {
        CreateRoom();

        foreach (var room in roomList)
        {
            CheckRoomDoor(room, room.transform.position);
        }
    }

最终效果
在这里插入图片描述
目前完整脚本
RoomGenerator.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoomGenerator : MonoBehaviour
{
    /// <summary>
    /// 方向
    /// </summary>
    public enum Direction
    {
        LEFT = 0,
        RIGHT = 1,
        TOP = 2,
        BOTTOM = 3
    }

    //基础房间预制体
    public GameObject baseRoom;

    //下次生成房间的方向
    private Direction direction;

    //房间最大个数
    public int maxCreateNum;

    //房间层级
    public LayerMask roomLayer;
    
    //当前房间列表
    private List<Room> roomList = new List<Room>();

    public GameObject startRoom;
    public GameObject endRoom;

    //生成点
    public Transform spawnPoint;
    //生成点偏移量
    public float xOffset, yOffset;
    //检测半径(当前位置是否有一个房间)
    public float roomColliderRadius;

    //起始房间颜色
    public Color startColor;
    //结束房间颜色
    public Color endColor;

    // Start is called before the first frame update
    void Start()
    {
        CreateRoom();

        foreach (var room in roomList)
        {
            CheckRoomDoor(room, room.transform.position);
        }

        startRoom = roomList[0].gameObject;
        endRoom = roomList[maxCreateNum - 1].gameObject;
        startRoom.GetComponent<SpriteRenderer>().color = startColor;
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    /// <summary>
    /// 随机创建房间方向
    /// </summary>
    void RandomDirection()
    {
        do
        {
            direction = (Direction) Random.Range(0, 4);

            switch (direction)
            {
                case Direction.LEFT:
                    spawnPoint.position += new Vector3(-xOffset, 0, 0);
                    break;
                case Direction.RIGHT:
                    spawnPoint.position += new Vector3(xOffset, 0, 0);
                    break;
                case Direction.BOTTOM:
                    spawnPoint.position += new Vector3(0, -yOffset, 0);
                    break;
                case Direction.TOP:
                    spawnPoint.position += new Vector3(0, yOffset, 0);
                    break;
            }

        } while (Physics2D.OverlapCircle(spawnPoint.position, roomColliderRadius, roomLayer));


    }

    /// <summary>
    /// 创建随机地图
    /// </summary>
    void CreateRoom()
    {
        for (int i = 0; i < maxCreateNum; i++)
        {
            CreateRoomObj(baseRoom, spawnPoint.position);
            RandomDirection();
        }
    }

    /// <summary>
    /// 创建房间
    /// </summary>
    /// <param name="room">房间预制体对象</param>
    /// <param name="pos">位置</param>
    void CreateRoomObj(GameObject room, Vector3 pos)
    {
        GameObject obj = Instantiate(room, pos, Quaternion.identity);
        // obj.transform.position = pos;
        roomList.Add(obj.GetComponent<Room>());
    }

    /// <summary>
    /// 检测当前房间周围的房间数量
    /// </summary>
    /// <param name="room"></param>
    /// <param name="pos"></param>
    void CheckRoomDoor(Room room, Vector3 pos)
    {
        Collider2D left = Physics2D.OverlapCircle(pos + new Vector3(-xOffset, 0, 0), roomColliderRadius, roomLayer);
        Collider2D right = Physics2D.OverlapCircle(pos + new Vector3(xOffset, 0, 0), roomColliderRadius, roomLayer);
        Collider2D top = Physics2D.OverlapCircle(pos + new Vector3(0, yOffset, 0), roomColliderRadius, roomLayer);
        Collider2D bottom = Physics2D.OverlapCircle(pos + new Vector3(0, -yOffset, 0), roomColliderRadius, roomLayer);

        room.isLeft = left;
        room.isRight = right;
        room.isTop = top;
        room.isBottom = bottom;

        room.UpdateRoomState();
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(spawnPoint.position,roomColliderRadius);
    }
}

Room.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Room : MonoBehaviour
{
    //四个门
    public GameObject doorLeft, doorRight, doorTop, doorBottom;

    public bool isLeft;
    public bool isRight;
    public bool isTop;
    public bool isBottom;

    //门的数量
    public int doorNumber;



    void Awake()
    {
        foreach (Transform door in transform)
        {
            switch ((RoomGenerator.Direction)Convert.ToInt32(door.gameObject.name))
            {
                case RoomGenerator.Direction.LEFT:
                    doorLeft = door.gameObject;
                    break;
                case RoomGenerator.Direction.RIGHT:
                    doorRight = door.gameObject;
                    break;
                case RoomGenerator.Direction.TOP:
                    doorTop = door.gameObject;
                    break;
                case RoomGenerator.Direction.BOTTOM:
                    doorBottom = door.gameObject;
                    break;
            }   
        }
    }

    void Start()
    {
        doorLeft.SetActive(isLeft);
        doorRight.SetActive(isRight);
        doorBottom.SetActive(isBottom);
        doorTop.SetActive(isTop);


    }

    public void UpdateRoomState()
    {
        if (isLeft) doorNumber++;
        if (isRight) doorNumber++;
        if (isTop) doorNumber++;
        if (isBottom) doorNumber++;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值