Unity 判断格子是否在封闭空间内(房间中)

话不多说,先上效果:

白底表示格子(地板),蓝线表示包围框(墙)。

1、最简单的一种:

 2、中间漏缝:

3、复杂一点的:

 

原理讲解

1、定义一个所有需要检测的格子区域,待检测区域,当前检测区域
2、如果待检测区域为空,将待检测区域中随机一个点放入待检测区域中。如果待检测区域也为空,说明已经遍历完了
3、取出待检测区域中第一个点。向前后左右四个方向检测
  a、将取出的点从需要检测的格子区域中移除,从待检测区域中移除。
  b、如果该方向有墙,不处理。
  c、如果该方向没有墙,但是该方向下一个点不在需要检测的格子里,也不在当前检测区域中,说明已经超出边界。此时当前检测区域列表中的点,和当前待检测区域中的点,都不在封闭区域内。返回步骤2
  d、将该方向的下一个点加入待检测列表
4、重复步骤3,当待检测区域为空时,当前检测区域内的点,就是封闭区域内的点。此时重复步骤2
 

代码如下,之所以字典里存了Transform,是测试时改变颜色的,各位可以自行修改存储结构

我是将格子坐标*2,然后墙坐标就可以放在两个格子中间

比如,格子(0,0) 和格子(2,0)是挨着的,中间墙的坐标为(1,0)。

    //事先存好的所有点(坐标并非相邻,放大了两倍,方便取墙的坐标)
    //比如,格子(0,0) 和格子(2,0)是挨着的,中间墙的坐标为(1,0)
    Dictionary<int, Dictionary<int,Transform>> foundationMap = new Dictionary<int, Dictionary<int, Transform>>();
    //事先存好的所有墙
    Dictionary<int, Dictionary<int, Transform>> wallMap = new Dictionary<int, Dictionary<int, Transform>>();


    public void Calculate()
    {
        Dictionary<int, List<int>> list = new Dictionary<int, List<int>>();
        Dictionary<int, List<int>> closedMap = new Dictionary<int, List<int>>();

        
        foreach (var item in foundationMap)
        {
            foreach (var temp in item.Value.Keys)
            {
                if (!list.ContainsKey(item.Key))
                    list.Add(item.Key, new List<int>());
                list[item.Key].Add(temp);
            }
        }
        int x = 0, z = 0;
        foreach (var item in foundationMap)
        {
            foreach (var temp in item.Value.Keys)
            {
                x = item.Key;
                z = temp;
                break;
            }
            break;
        }
        if (foundationMap.Count > 0)
        {
            while (list.Count > 0)
            {
                Dictionary<int, List<int>> areas = new Dictionary<int, List<int>>();
                Dictionary<int, List<int>> waitChecks = new Dictionary<int, List<int>>
                    {
                        { x, new List<int>() }
                    };
                waitChecks[x].Add(z);
                bool outOfRange = false;
                while (waitChecks.Count > 0)
                {
                    int _x = 0, _z = 0;
                    foreach (var item in waitChecks)
                    {
                        _x = item.Key;
                        _z = item.Value[0];
                        break;
                    }
                    waitChecks[_x].Remove(_z);
                    if (waitChecks[_x].Count == 0)
                        waitChecks.Remove(_x);

                    list[_x].Remove(_z);
                    if (list[_x].Count == 0)
                        list.Remove(_x);

                    if (!areas.TryGetValue(_x, out List<int> m1) || !m1.Contains(_z))
                    {
                        if (!areas.ContainsKey(_x))
                            areas.Add(_x, new List<int>());
                        areas[_x].Add(_z);

                        //这个是检测周围4个方向的点的坐标
                        int[,] tb = new int[4, 2]
                        {
                                { _x,_z + 2},
                                {_x + 2,_z },
                                {_x,_z - 2 },
                                {_x -2,_z }
                        };
                        
                        //这个是检测周围4个方向的点的墙
                        int[,] tb1 = new int[4, 2]
                        {
                                { _x,_z + 1},
                                {_x + 1,_z },
                                {_x,_z - 1 },
                                {_x -1,_z }
                        };

                        for (int i = 0; i < 4; i++)
                        {
                            if (!wallMap.TryGetValue(tb1[i, 0], out Dictionary<int,Transform> m2) || !m2.ContainsKey(tb1[i, 1]))
                            {
                                _x = tb[i, 0];
                                _z = tb[i, 1];

                                if (list.TryGetValue(_x, out List<int> m3) && m3.Contains(_z))
                                {
                                    if (!waitChecks.ContainsKey(_x))
                                        waitChecks.Add(_x, new List<int>());
                                    if (!waitChecks[_x].Contains(_z))
                                        waitChecks[_x].Add(_z);
                                }
                                else if (!areas.TryGetValue(_x, out List<int> m4) || !m4.Contains(_z))
                                {
                                    outOfRange = true;
                                    break;
                                }
                            }
                        }
                        if (outOfRange)
                            break;
                    }
                }

                if (!outOfRange)
                {
                    foreach (var item in areas)
                    {
                        foreach (var temp in item.Value)
                        {
                            if (!closedMap.ContainsKey(item.Key))
                                closedMap.Add(item.Key, new List<int>());
                            closedMap[item.Key].Add(temp);
                        }
                    }
                }

                foreach (var item in list)
                {
                    x = item.Key;
                    z = item.Value[0];
                    break;
                }
            }
        }
        foreach (var item in closedMap)
        {
            for (var i = 0; i < item.Value.Count; i++)
            {
                //封闭区域的每一个点
                //foundationMap[item.Key][item.Value[i]].GetComponent<Image>().color = Color.green;
            }
        }
    }

如果事先没有检测点格子,比如只拉了墙,要自动生成房间,这时也可以使用此方法。取出矩形区域内的所有格子放入待检测列表中,也可以计算出所有封闭区域。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值