Roguelike随机地下城 | 二、设置门和优化最终房间的选择

Roguelike随机地下城

设置门&优化最终房间的选择


一、设置门&优化最终房间的选择

首先我们先添加四个方向的门。
点击Prefab,然后我们建立一个方形暂时代替我们的门。
右键|creat|2D|Sprites|Square。
在这里插入图片描述
然后拖入我们的Prefab中复制三个,放置到如图的位置。
在这里插入图片描述
接下来建立一个Room脚本挂载到Prefab上。
首先我们先声明这四个GameObject。

    public GameObject doorLeft,doorRight,doorUp,doorDown;

回到Unity对齐进行赋值。
这里将会用到Sorting Layer,他表示我们的显示层,为了我们的门可以显示出来,我们这里建立一个Room层,同时把Ground和Player层建立。
在这里插入图片描述
在这里插入图片描述
接下来我们将判断这个房间上下左右是否有门,我们要生成四个布尔值。

    public bool roomLeft,roomRight, roomUp, roomDown;

然后我们在之后需要考虑它们是否显示出来,所以我们在Start方法中定义一下显示的方法。

    void Start()
    {
        doorLeft.SetActive(roomLeft);
        doorRight.SetActive(roomRight);
        doorUp.SetActive(roomUp);
        doorDown.SetActive(roomDown);
    }

我们会判断当前的房间上下左右是否有房间,有房间就显示门,没有就不显示。
接下来我们判断上下左右是否有房间。
为了获得每一个房间上面的变量,将我们一开始设置的rooms的List的类型改成Room,下面的地方并做适当的更改。

    public List<Room> rooms = new List<Room>();
     void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //改变point位置
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            {
                endRoom = room.gameObject;
            }
        }
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

接下来我们要设置一个方法,来判断上下左右是否有房间,并对Room进行赋值。
方法中需要加入两个参数,一个用于识别Room,一个用于获得房间的位置。

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);
    }

调用这个方法,可以先将之前找到最后一个房间的方法注释掉。

     void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //改变point位置
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
                //endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

这样我们的门就设置好了。

二、优化最终房间的选择

我们要选择离我们出生点最远的那个房间,所以接下来我添加一个Text方便显示,每一个房间到我出生点房间的网格的步数。
首先为我们的Prefab建立一个画布Canvas在建立一个Text,把文字改为0。
在这里插入图片描述
设置好之后,我们要在脚本中获得这个Text,并且更改他的数值。
这里我们在Room脚本中新建一个方法。

    public void UpdateRoom()
    {

    }

我们的步数怎么计算呢?
可以通过我们当前房间的坐标,x、y值除以我们的x、y的偏移量就可以得到步数!
我们要获得这个数值,所以一开始先定义一个变量。
因为我们的坐标可能是负数,所以我们要用到数学方法中的绝对值。
这里我为了方便直接除以了固定的值。

    public int stepToStart;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));
    }

然后我们定义一个变量来获得我们的文本。
然后让这个文本显示我们的stepToStart。

    public Text text;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();
    }

然后我们这个方法要在RoomGenerator脚本中的SetupRoom方法中调用。

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);

        newRoom.UpdateRoom();
    }

接下来我们怎么设置我们的最终房间?
我们的思路是找到步数最大的和次大的房间,找到只有一个门的房间,随机选择一个当作最终房间,如果没有只有一个门的房间,那么我们就随机选择一个步数最大的房间当作最终房间。

接下来要设计三个列表,一个用来存放步数最大的房间,一个存放步数次大的房间,一个存放两种房间只有一个门的房间。
首先回到Room脚本,首先我们先找到一个房间有几个门。
我们先定义一个变量,用来记录门的数量。
然后我们有四个布尔值,每有一个布尔值为true,我们的数量就加1。

    public int doorNumber;
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();

        if (roomUp)
            doorNumber++;
        if (roomDown)
            doorNumber++;
        if (roomLeft)
            doorNumber++;
        if (roomRight)
            doorNumber++;
    }

接下来回到RoomGenerator脚本中定义三个数值。

    List<GameObject> farRooms = new List<GameObject>();
    List<GameObject> lessFarRooms = new List<GameObject>();
    List<GameObject> oneWayRooms = new List<GameObject>();

然后我们再定义一个变量,用来表示步数最大的那个数字。

    public int maxStep;

新定义一个方法,用来找到最终的房间。
首先我们用一个for循环,找到所有房间里面步数最大的房间,把他加入farRooms数组中,把次大的房间放入lessFarRooms数组中。

        //获得最大数值
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].stepToStart > maxStep)
                maxStep = rooms[i].stepToStart;
        }
        //获得最大数值房间和次大数值房间
        foreach (var room in rooms)
        {
            if (room.stepToStart == maxStep)
                farRooms.Add(room.gameObject);
            if(room.stepToStart == maxStep-1)
                lessFarRooms.Add(room.gameObject);
        }

接下来判断数组中有没有只有一个门的房间。


        for (int i = 0; i < farRooms.Count; i++)
        {
            if (farRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(farRooms[i]);
        }

        for (int i = 0; i < lessFarRooms.Count; i++)
        {
            if (lessFarRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(lessFarRooms[i]);
        }

接下来如果两个oneWayRooms数组中有数值,就随机在这个数组中随机取一个数值,作为对应的最终房间,如果数值为0,则在farRooms数值中随机取一个数值,作为对应的最终房间。

        if (oneWayRooms.Count != 0)
        {
            endRoom = oneWayRooms[Random.Range(0, oneWayRooms.Count)];
        }
        else
        {
            endRoom = farRooms[Random.Range(0, farRooms.Count)];
        }

最后在上面调用就可以了。

    void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //改变point位置
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
            //    endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        FindEndRoom();
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

最后运行一下,效果如下。
在这里插入图片描述


源码

现阶段我们的完整代码如下:
RoomGenerator脚本

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

public class RoomGenerator : MonoBehaviour
{
    public enum Direction {up,down,left,right };
    public Direction direction;

    [Header("房间信息")]
    public GameObject roomPrefab;
    public int rooNumber;
    public Color startColor,endColor;
    private GameObject endRoom;

    [Header("位置控制")]
    public Transform generatorPoint;
    public float xOffset;
    public float yOffset;
    public LayerMask roomLayer;

    public int maxStep;

    public List<Room> rooms = new List<Room>();

    List<GameObject> farRooms = new List<GameObject>();
    List<GameObject> lessFarRooms = new List<GameObject>();
    List<GameObject> oneWayRooms = new List<GameObject>();
    // Start is called before the first frame update
    void Start()
    {
        for (int i = 0; i < rooNumber; i++)
        {
            rooms.Add(Instantiate(roomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            //改变point位置
            ChangePointPos();
        }

        rooms[0].GetComponent<SpriteRenderer>().color = startColor;

        endRoom = rooms[0].gameObject;
        foreach (var room in rooms)
        {
            //if (room.transform.position.sqrMagnitude > endRoom.transform.position.sqrMagnitude)
            //{
            //    endRoom = room.gameObject;
            //}
            SetupRoom(room,room.transform.position);
        }
        FindEndRoom();
        endRoom.GetComponent<SpriteRenderer>().color = endColor;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.anyKeyDown)
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

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

            switch (direction)
            {
                case Direction.up:
                    generatorPoint.position += new Vector3(0, yOffset, 0);
                    break;
                case Direction.down:
                    generatorPoint.position += new Vector3(0, -yOffset, 0);
                    break;
                case Direction.left:
                    generatorPoint.position += new Vector3(-xOffset, 0, 0);
                    break;
                case Direction.right:
                    generatorPoint.position += new Vector3(xOffset, 0, 0);
                    break;
            }
        }while (Physics2D.OverlapCircle(generatorPoint.position,0.2f,roomLayer));
    }

    public void SetupRoom(Room newRoom,Vector3 roomPosition)
    {
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yOffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yOffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xOffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xOffset, 0, 0), 0.2f, roomLayer);

        newRoom.UpdateRoom();
    }

    public void FindEndRoom()
    {
        //获得最大数值
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].stepToStart > maxStep)
                maxStep = rooms[i].stepToStart;
        }
        //获得最大数值房间和次大数值房间
        foreach (var room in rooms)
        {
            if (room.stepToStart == maxStep)
                farRooms.Add(room.gameObject);
            if(room.stepToStart == maxStep-1)
                lessFarRooms.Add(room.gameObject);
        }

        for (int i = 0; i < farRooms.Count; i++)
        {
            if (farRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(farRooms[i]);
        }

        for (int i = 0; i < lessFarRooms.Count; i++)
        {
            if (lessFarRooms[i].GetComponent<Room>().doorNumber == 1)
                oneWayRooms.Add(lessFarRooms[i]);
        }

        if (oneWayRooms.Count != 0)
        {
            endRoom = oneWayRooms[Random.Range(0, oneWayRooms.Count)];
        }
        else
        {
            endRoom = farRooms[Random.Range(0, farRooms.Count)];
        }
    }
}

Room脚本

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

public class Room : MonoBehaviour
{
    public GameObject doorLeft,doorRight,doorUp,doorDown;

    public bool roomLeft,roomRight, roomUp, roomDown;

    public Text text;

    public int stepToStart;

    public int doorNumber;
    // Start is called before the first frame update
    void Start()
    {
        doorLeft.SetActive(roomLeft);
        doorRight.SetActive(roomRight);
        doorUp.SetActive(roomUp);
        doorDown.SetActive(roomDown);
    }

    // Update is called once per frame
    public void UpdateRoom()
    {
        stepToStart = (int)(Mathf.Abs(transform.position.x / 18) + Mathf.Abs(transform.position.y / 9));

        text.text = stepToStart.ToString();

        if (roomUp)
            doorNumber++;
        if (roomDown)
            doorNumber++;
        if (roomLeft)
            doorNumber++;
        if (roomRight)
            doorNumber++;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 杭州行政区划shp文件是指包含了杭州市各级行政区划边界的矢量数据文件。shp文件是GIS(地理信息系统)中常用的数据格式之一,可以用于在地图上显示和分析行政区划信息。 杭州市作为浙江省的省会城市,下辖有市辖区、县级市和县三级行政区划。市辖区包括了拱墅区、西湖区、上城区、下城区、江干区、滨江区、余杭区和萧山区等8个区;县级市有富阳市和临安市;县则有建德市、桐庐县、淳安县、杭州市余杭区等。 杭州行政区划shp文件中的每个区域都会有对应的地理边界信息,可以用于制作杭州的各级行政区划地图,并在地图上显示不同区域的边界线。通过该文件,我们可以清楚地了解杭州市各级行政区划的范围和分布情况。 使用杭州行政区划shp文件,我们可以进行各种地理空间分析,例如计算不同区域的面积和人口密度,制作分级统计图,分析各个区域的人口分布情况等。此外,还可以在地图上添加其他地理要素,如道路、河流等,以便更好地理解和分析杭州市的行政区划信息。 总之,杭州行政区划shp文件是一个重要的地理数据文件,可以帮助我们更好地了解和分析杭州市的行政区划情况,为城市规划、交通规划、人口统计等提供基础数据支持。 ### 回答2: 杭州市行政区划shp文件是一种常见的地理信息文件格式,用于存储杭州市的行政边界和相关属性信息。该文件可以被地理信息系统(GIS)软件使用,用于展示、分析和处理行政区划方面的数据。 杭州市是中国浙江省的省会城市,下辖10个市辖区,包括拱墅区、西湖区、上城区、下城区、江干区、滨江区、萧山区、余杭区、富阳区和临安区。每个市辖区都有自己的行政边界,以及一些属性信息如名称、面积、人口等。 通过杭州市行政区划shp文件,我们可以获得每个市辖区的边界坐标数据,这些数据可以用于绘制地图或进行空间分析。地理信息系统软件可以将该shp文件导入到地图界面上,从而将杭州市的行政区划展示出来。我们可以根据不同的属性信息对市辖区进行着色、标注等操作,从而更好地理解杭州市的行政区划情况。 此外,杭州市行政区划shp文件也可以在各种研究和规划中发挥重要的作用。在城市规划领域,通过对行政区划shp文件的分析,可以评估各个市辖区的人口密度、土地利用情况等,为城市发展和资源配置提供参考。在灾害管理方面,利用行政区划shp文件可以更好地了解各个市辖区的边界范围,帮助进行灾害防控和应急救援的规划。 综上所述,杭州市行政区划shp文件是一种重要的地理信息数据文件,可以被广泛应用于地理信息系统、城市规划、灾害管理等领域,帮助我们更好地理解和利用杭州市的行政区划信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值