Unity日常

unity中判断一个点是否在多边形范围内

在游戏怪物AI中,怪物一般都会有巡逻这一动作,在没有发现玩家时怪物就会在自己的巡逻范围内移动。这里该如何检测怪物是否在自己的巡逻范围内呢?这里假定巡逻范围为一个多边形区域。

先来看一张图

在这个由点A,B,C,D构成的四边形是巡逻区域,点E,F,K为我们要检测的位置点。点E在四边形内,E和F都在四边形外,这里分别在点E,F,K的水平方向上画一条横线。我们发现点K和点E都与四边行有两个交点,点K的交点(n,m)都在右侧,且右侧数量为偶数。点E的交点(i,j)在E点两侧数量为奇数。

再来看一张图

20160803181004

在这个多边形中点I,J,K 是我们要检测的点,点J在范围内,点K,I不在范围内。

我们发现在上图中点J与多边形有两个交点(P,Q),左右两边交点数量奇数

点I与多边形有四个交点(L,S,R,M),左右两边的交点数量偶数

点K与多边形有四个交点(N,T,O,V),左右两边的交点数量偶数

也就是说判断点是否在多边形范围内,只需要判断该点在水平方向或垂直方向上与多边形的交点与该点左右两边的数量即可。

如果检测点左右两边与多边形交点的数量为奇数,那么就在多边形范围内,为偶数就不在范围内。

在Unity代码实现上。只需要判断测试点的水平方向与多边形的交点数量就行了。

 
    ///<summary>
    /// 计算一个点是否在一个多边形范围内
    /// 如果过该点的线段与多边形的交点不为零且距该点左右方向交点数量都为奇数时  该点再多边形范围内
    /// <summary>
    /// <param name="point">测试点</param>
    /// <param name="vertexs">多边形的顶点集合</param>
    /// <returns><returns>
    public static bool PolygonIsContainPoint(Vector3 point, List<Vector3> vertexs)
    {
        //for (int i = 0; i < vertexs.Count; i++)
        //{
        //    if (point.x == vertexs[i].x && point.z == vertexs[i].z)
        //    {
        //        return true;
        //    }
        //}

        //判断测试点和横坐标方向与多边形的边的交叉点

        int leftNum = 0;  //左方向上的交叉点数
        int rightNum = 0;  //右方向上的交叉点数
        int index = 1;
        for (int i = 0; i < vertexs.Count; i++) { 
            if (i == vertexs.Count - 1) { index = -i; } 
            //找到相交的线段 
            if (point.z >= vertexs[i].z && point.z < vertexs[i + index].z || point.z < vertexs[i].z && point.z >= vertexs[i + index].z)
            {
                Vector3 vecNor = (vertexs[i + index] - vertexs[i]);
                  
                
                //处理直线方程为常数的情况
                if (vecNor.x == 0.0f)
                {
          
                    if (vertexs[i].x < point.x)
                    {
                        leftNum++;
                    }
                    else if (vertexs[i].x == point.x)
                    { }
                    else
                    {
                        
                        rightNum++;
                    }

                }
                else {
                    vecNor = vecNor.normalized;
                    float k = vecNor.z / vecNor.x;
                    //print(vertexs[i + index]);
                    float b = vertexs[i].z - k * vertexs[i].x;
                
                    if ((point.z - b) / k < point.x)
                    {
                        leftNum++;
                        
                    }
                    else if ((point.z - b) / k == point.x)
                    {

                    }
                    else
                    {
                        rightNum++;
                       
                    }

                }

            }

        }
        
        if (leftNum % 2 != 0 || rightNum % 2 != 0)
        {
            return true;
        }
        return false;
    }

在这里我忽略了Y轴,只考虑二维情况。
首先判断测试点z轴的值,是否在每条边的值域内。
将测试点的x值代入每个边的直线方程,结果比测试点x值小就在左边,否则在右边。
最后判断奇偶数就行了。

(5)

本文由 树莓屋 作者:Berry贝锐 发表,转载请注明来源!

关键词:

热评文章

发表评论