Unity2D Rogue地下城房间随机生成 第二期

1.目标

       在第一期随机地图生成中,我们已经完成了我们想要的地图的随机生成功能,在这一期中我们将来完善每一个房间的随机生成,先来看效果。

          

       可以自行添加房间中想要生成的物体类型(在这里我们有障碍物和宝箱两种),我们可以设置它们的生成数量,并且它们是不会重叠的,且我们可以在tileMap中设置它们的生成范围,以确保不会出现障碍物堵住房间出入口的情况。

       可以自行设置障碍物和宝箱出现的区域,且设置方便简单,直接使用TilePalette编辑。

    

        可以直接使用TilePalette去编辑我们的障碍物和宝箱出现的区域,非常方便。

   

2.实现原理

    可以看到,我们的TileMap是由边长为1的正方形构成,每一个Tile的长宽相等,且间距相等。

我们可以把整个房间看作是由一个个边长为1的tile拼接而成。

     Physics2D.OverlapCircleAll Unity自带的方法,该方法会返回一个Collider2D[]的数组(检测某一点一定范围内的拥有碰撞器的且处于参数中指定的LayerMask的游戏物体的数组)  

      我们来看看我们的代码该怎么写,首先填入一个checkPos(需要检测的位置),在填入一个检测范围(该方法为圆形检测,我们每一个方块的边长为1,每一个tile的生成位置都在每一个方块的正中心,所以我们的圆形检测的半径必须得小于0.5(不然会检测到其他块),在这里我们直接填入0.1),在第三个参数LayerMask中填入我们想要检测的物体的Layer,在这里我们想要检测物体是否带有ChestSpanwerLayerMask,也就是检测该位置是否是一个宝箱生成的预设位置。

     我们先不用去管if语句块中的内容,来看看我们该怎么去设置ChestSpanwerLayerMask。

      在Room脚本中设置 ChestSpawnerLayerMask。

       在整体的TileMap下,设置你需要生成的障碍物或宝箱之类的Tile的位置,并为其挂载上不同的Layer与碰撞器,然后由于房间是由一个个边长为1的小方块组成的,那么我们很容易的就能去遍历所有房间中的小方块的中心位置,在每一个中心位置做一个OverlapCircleAll,根据OverlapCircleAll的来确定是否要在该位置生成障碍物或宝箱。

3.完整代码与项目设置

public class Room : MonoBehaviour
{
    public int stepTostart = -1;

    public GameObject rightDoor;
    public GameObject leftDoor;
    public GameObject topDoor;
    public GameObject bottomDoor;

    public TextMeshProUGUI myText;


    [Header("房间长宽")]
    public float X = 16;//根据你自己的房间的长宽自行设置,每一个小方块的边长为1,很容易得出
    public float Y = 8;

    [Header("房间内实体")]
    public LayerMask ObstalceSpawnerLayerMask;
    public int ObstacleCount = 10; // 设置生成障碍物的数量
    public GameObject Obstacle;
    public LayerMask ChestSpawnerLayerMask;
    public int ChestCount = 1;
    public GameObject Chest;
    // Start is called before the first frame update
    void Awake()
    {
        GameObject canvas = this.transform.Find("Canvas").gameObject;
        if (canvas != null)
        {
            myText = canvas.transform.Find("Text").GetComponent<TextMeshProUGUI>();
        }
        else
        {
            Debug.LogError("Canvas not found. Please check the spelling and the object hierarchy.");
        }
    }
    private void Start()
    {
        List<Vector3> possiblePositions = new List<Vector3>();//障碍物预生成点
        List<Vector3> chestPositions=new List<Vector3>();//宝箱预生成点
        for (int i = 0; i < X; i++)//两层for循环 遍历所有房间中的位置
        {
            for (int j = 0; j < Y; j++)
            {
                Vector3 checkPos = new Vector3(transform.position.x - (X / 2 - 0.5f) + i, transform.position.y - (Y / 2 - 0.5f)+j,0);//检查点
                if (Physics2D.OverlapCircleAll(checkPos, 0.1f, ObstalceSpawnerLayerMask).Length > 0)
                {
                    //GameObject newObstacle = Instantiate(Obstacle, new Vector3(transform.position.x - (X / 2 - 0.5f) + i, transform.position.y - (Y / 2 - 0.5f) + j, 0), Quaternion.identity);
                    //newObstacle.transform.parent = this.transform;
                    possiblePositions.Add(checkPos);
                }
                if(Physics2D.OverlapCircleAll(checkPos, 0.1f, ChestSpawnerLayerMask).Length > 0)
                {
                    chestPositions.Add(checkPos);
                    Debug.Log("find chest");
                }
            }
        }
        for (int i = 0; i < ObstacleCount && possiblePositions.Count > 0; i++)
        {
            int randomIndex = Random.Range(0, possiblePositions.Count);
            GameObject newObstacle = Instantiate(Obstacle, possiblePositions[randomIndex], Quaternion.identity);
            newObstacle.transform.parent = this.transform;
            possiblePositions.RemoveAt(randomIndex);
        }
        for (int i = 0; i < ChestCount && chestPositions.Count > 0; i++)
        { //根据设置的生成数量从预生成点中随机抽取位置生成
            int randomIndex = Random.Range(0, chestPositions.Count);
            GameObject newObstacle = Instantiate(Chest, chestPositions[randomIndex], Quaternion.identity);
            newObstacle.transform.parent = this.transform;
            chestPositions.RemoveAt(randomIndex);
        }
    }
    // Update is called once per frame
    void Update()
    {

    }

    public void ChangeText()
    {
        if (myText != null)
        {
            myText.text = stepTostart.ToString();
        }
        else
        {
            Debug.LogError("myText is null. Did you forget to attach a TextMeshPro component?");
        }
    }
}

4.总结

      整体功能的实现由于本人的技术不足,实现逻辑都非常暴力,整体性能消耗较大,如果有更好的方法欢迎提出,由于图文讲解不是很清晰与方便,如果本篇文章讲解的内容你很感兴趣,但是在阅读后并不是很能理解该功能的实现过程,欢迎留言告知,如果告知人数较多,将会在其他平台以视频形式制作一期教程。

     如有错漏 恳请指出 谢谢

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity随机生成障碍物,可以使用代码来实现。以下是一个简单的示例: 1. 创建一个空对象(例如,命名为ObstacleSpawner),并将其放置在场景中。 2. 在该对象上添加一个脚本(例如,命名为ObstacleGenerator)。 3. 在脚本中定义障碍物的预制体(例如,命名为ObstaclePrefab)。 4. 编写代码,在Start或Update方法中生成障碍物。可以使用Random类来生成随机位置和随机旋转角度。 下面是一个示例代码: ``` public class ObstacleGenerator : MonoBehaviour { public GameObject ObstaclePrefab; public Vector2 SpawnRangeX; public Vector2 SpawnRangeY; public Vector2 RotationRange; void Start() { GenerateObstacle(); } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { GenerateObstacle(); } } void GenerateObstacle() { Vector3 spawnPosition = new Vector3(Random.Range(SpawnRangeX.x, SpawnRangeX.y), Random.Range(SpawnRangeY.x, SpawnRangeY.y), 0); Quaternion spawnRotation = Quaternion.Euler(0, 0, Random.Range(RotationRange.x, RotationRange.y)); Instantiate(ObstaclePrefab, spawnPosition, spawnRotation); } } ``` 在上述代码中,我们定义了ObstaclePrefab、SpawnRangeX、SpawnRangeY和RotationRange变量。ObstaclePrefab变量是障碍物的预制体,SpawnRangeX和SpawnRangeY变量是障碍物生成的范围,RotationRange变量是障碍物生成时的旋转角度范围。 在Start方法中,我们生成了第一个障碍物。在Update方法中,如果按下了空格键,我们会再次生成一个障碍物。 在GenerateObstacle方法中,我们使用Random.Range方法来生成随机位置和随机旋转角度。然后,我们使用Instantiate方法来创建一个新的障碍物实例。 请注意,此示例代码仅用于演示目的。您可以根据自己的需求进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值