IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> [Unity]Roguelike随机地图生成(一) -> 正文阅读

[游戏开发][Unity]Roguelike随机地图生成(一)

初步随机地图生成

基础房间生成

首先需要确定每次房间生成都是在上一个房间的哪个方向上生成,为此需要声明一个枚举值来记录上下左右四个方向
创建脚本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++;
    }
}

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-10-12 23:48:06  更:2021-10-12 23:49:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 2:47:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码