private bool TriangleContainsVertexInList(int indexPrev, int indexCurr, int indexNext, NativeLinkedList <int> list)
        {
            for (NativeLinkedList <int> .Enumerator currIndexNode = list.Head; currIndexNode.IsValid; currIndexNode.MoveNext())
            {
                NativeLinkedList <int> .Enumerator prevIndexNode = (currIndexNode.Prev.IsValid) ? currIndexNode.Prev : list.Tail;
                NativeLinkedList <int> .Enumerator nextIndexNode = (currIndexNode.Next.IsValid) ? currIndexNode.Next : list.Head;

                bool isCurrentConvex = Math2DUtils.IsVertexConvex(Polygon[prevIndexNode.Value], Polygon[currIndexNode.Value], Polygon[nextIndexNode.Value], true);
                if (isCurrentConvex)
                {
                    continue;
                }

                int currIndexToCheck = currIndexNode.Value;
                if (currIndexToCheck == indexPrev || currIndexToCheck == indexCurr || currIndexToCheck == indexNext)
                {
                    continue;
                }

                if (Math2DUtils.IsInsideTriangle(Polygon[currIndexToCheck], Polygon[indexPrev], Polygon[indexCurr], Polygon[indexNext]))
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #2
0
    /// <summary>
    /// 设置朝向
    /// </summary>
    /// <param name="dir">忽视z轴</param>
    public override void SetForward(Vector3 dir)
    {
        //转换成角度
        float angle = Math2DUtils.Point2Radians(dir.x, dir.y);

        this.SetRotate2D(angle);
    }
Пример #3
0
    /// <summary>
    /// 判断是否可移动
    /// </summary>
    /// <param name="tile"></param>
    /// <returns></returns>
    private bool checkCanMove(PathGrid tile, Rect collide_rect)
    {
        if (tile == null)
        {
            return(false);
        }

        if (!tile.walkable && Math2DUtils.intersectRect(tile.rect, collide_rect))
        {
            return(false);
        }
        return(true);
    }
        private void Triangulate(int polygonIndex, NativeLinkedList <int> list)
        {
            int trisIndex = 0;

            for (int pi = 0; pi < polygonIndex; ++pi)
            {
                trisIndex += Polygons.GetPolygonHolesNum(pi) * 2 + Polygons.GetPolygonNumVertices(pi) - 2;
            }
            trisIndex *= 3;

            while (list.Length > 2)
            {
                bool hasRemovedEar = false;

                int currListIndex = 0;
                NativeLinkedList <int> .Enumerator currIndexNode = list.Head;
                for (int i = 0; i < list.Length; ++i)
                {
                    NativeLinkedList <int> .Enumerator prevIndexNode = (currIndexNode.Prev.IsValid) ? currIndexNode.Prev : list.Tail;
                    NativeLinkedList <int> .Enumerator nextIndexNode = (currIndexNode.Next.IsValid) ? currIndexNode.Next : list.Head;

                    bool isCurrentConvex = Math2DUtils.IsVertexConvex(Polygons[prevIndexNode.Value], Polygons[currIndexNode.Value], Polygons[nextIndexNode.Value], true);
                    if (isCurrentConvex)
                    {
                        bool triangleContainsAVertex = TriangleContainsVertexInList(prevIndexNode.Value, currIndexNode.Value, nextIndexNode.Value, list);
                        if (!triangleContainsAVertex)
                        {
                            OutTriangles[trisIndex]     = nextIndexNode.Value;
                            OutTriangles[trisIndex + 1] = currIndexNode.Value;
                            OutTriangles[trisIndex + 2] = prevIndexNode.Value;
                            trisIndex += 3;

                            list.Remove(currIndexNode);

                            hasRemovedEar = true;
                            break;
                        }
                    }

                    currListIndex = (currListIndex + 1) % list.Length;
                    currIndexNode = list.GetEnumeratorAtIndex(currListIndex);
                }

                if (!hasRemovedEar)
                {
                    return;
                }
            }
        }
        public void Execute()
        {
            NativeLinkedList <int> hullVertices = StorePolygonContourAsLinkedList();

            #region Removing Holes
            //create the array containing the holes data
            NativeArray <ECHoleData> holes = GetHolesDataSortedByMaxX();
            //remove holes
            for (int hi = 0; hi < holes.Length; ++hi)
            {
                ECHoleData hole = holes[hi];
                var        intersectionEdgeP0 = hullVertices.GetEnumerator();
                var        intersectionEdgeP1 = hullVertices.GetEnumerator();
                float2     intersectionPoint  = new float2(float.MaxValue, hole.BridgePoint.y);

                for (var currentHullVertex = hullVertices.Head; currentHullVertex.IsValid; currentHullVertex.MoveNext())
                {
                    var nextHullVertex = (currentHullVertex.Next.IsValid) ? currentHullVertex.Next : hullVertices.Head;

                    float2 currPoint = Polygon[currentHullVertex.Value];
                    float2 nextPoint = Polygon[nextHullVertex.Value];

                    //M is to the left of the line containing the edge (M is inside the outer polygon)
                    bool isMOnLeftOfEdgeLine = (Math2DUtils.LineSide(hole.BridgePoint, currPoint, nextPoint) < 0f);
                    if (isMOnLeftOfEdgeLine)
                    {
                        continue;
                    }

                    // at least one point must be to right of the hole bridge point for intersection with ray to be possible
                    if (currPoint.x < hole.BridgePoint.x && nextPoint.x < hole.BridgePoint.x)
                    {
                        continue;
                    }

                    if (currPoint.y > hole.BridgePoint.y == nextPoint.y > hole.BridgePoint.y)
                    {
                        continue;
                    }

                    float intersectionX = nextPoint.x; // if line p0,p1 is vertical
                    if (math.abs(currPoint.x - nextPoint.x) > float.Epsilon)
                    {
                        float intersectY = hole.BridgePoint.y;
                        float gradient   = (currPoint.y - nextPoint.y) / (currPoint.x - nextPoint.x);
                        float c          = nextPoint.y - gradient * nextPoint.x;
                        intersectionX = (intersectY - c) / gradient;
                    }

                    if (intersectionX < intersectionPoint.x)
                    {
                        intersectionPoint.x = intersectionX;
                        intersectionEdgeP0  = currentHullVertex;
                        intersectionEdgeP1  = nextHullVertex;
                    }
                }

                var selectedHullBridgePoint = hullVertices.GetEnumerator();
                //If I is a vertex of the outer polygon, then M and I are mutually visible
                if (Math2DUtils.SamePoints(intersectionPoint, Polygon[intersectionEdgeP0.Value]))
                {
                    selectedHullBridgePoint = intersectionEdgeP0;
                }
                else if (Math2DUtils.SamePoints(intersectionPoint, Polygon[intersectionEdgeP1.Value]))
                {
                    selectedHullBridgePoint = intersectionEdgeP1;
                }
                else
                {
                    //Select P to be the endpoint of maximum x-value for this edge
                    var P = (Polygon[intersectionEdgeP0.Value].x > Polygon[intersectionEdgeP1.Value].x) ? intersectionEdgeP0 : intersectionEdgeP1;

                    bool  existReflexVertexInsideMIP = false;
                    float minAngle = float.MaxValue;
                    float minDist  = float.MaxValue;
                    for (var currOuterPolygonVertex = hullVertices.Head; currOuterPolygonVertex.IsValid; currOuterPolygonVertex.MoveNext())
                    {
                        if (currOuterPolygonVertex.Value == P.Value)
                        {
                            continue;
                        }

                        var nextOuterPolygonVertex = (currOuterPolygonVertex.Next.IsValid) ? currOuterPolygonVertex.Next : hullVertices.Head;
                        var prevOuterPolygonVertex = (currOuterPolygonVertex.Prev.IsValid) ? currOuterPolygonVertex.Prev : hullVertices.Tail;

                        if (Math2DUtils.IsVertexReflex(
                                Polygon[prevOuterPolygonVertex.Value],
                                Polygon[currOuterPolygonVertex.Value],
                                Polygon[nextOuterPolygonVertex.Value],
                                true))
                        {
                            bool isInsideMIPTriangle = Math2DUtils.IsInsideTriangle(Polygon[currOuterPolygonVertex.Value],
                                                                                    hole.BridgePoint,
                                                                                    intersectionPoint,
                                                                                    Polygon[P.Value]);
                            existReflexVertexInsideMIP |= isInsideMIPTriangle;

                            if (isInsideMIPTriangle)
                            {
                                //search for the reflex vertex R that minimizes the angle between (1,0) and the line segment M-R
                                float2 MR       = Polygon[currOuterPolygonVertex.Value] - hole.BridgePoint;
                                float  angleMRI = math.atan2(MR.y, MR.x);
                                if (angleMRI < minAngle)
                                {
                                    selectedHullBridgePoint = currOuterPolygonVertex;
                                    minAngle = angleMRI;
                                }
                                else if (math.abs(angleMRI - minAngle) <= float.Epsilon)
                                {
                                    //same angle
                                    float lengthMR = math.length(MR);
                                    if (lengthMR < minDist)
                                    {
                                        selectedHullBridgePoint = currOuterPolygonVertex;
                                        minDist = lengthMR;
                                    }
                                }
                            }
                        }

                        if (!existReflexVertexInsideMIP)
                        {
                            selectedHullBridgePoint = P;
                        }
                    }
                }

                hullVertices.InsertAfter(selectedHullBridgePoint, selectedHullBridgePoint.Value);
                for (int i = hole.BridgePointIndex - hole.HoleFirstIndex, count = 0;
                     count < hole.HoleLength;
                     i = (i + hole.HoleLength - 1) % hole.HoleLength, ++count)
                {
                    hullVertices.InsertAfter(selectedHullBridgePoint, i + hole.HoleFirstIndex);
                }
                hullVertices.InsertAfter(selectedHullBridgePoint, hole.BridgePointIndex);
            }
            holes.Dispose();
            #endregion

            Triangulate(hullVertices);
            hullVertices.Dispose();
        }
Пример #6
0
    /// <summary>
    /// 寻路接口
    /// </summary>
    /// <param name="start_x"></param>
    /// <param name="start_y"></param>
    /// <param name="target_x"></param>
    /// <param name="target_y"></param>
    /// <param name="width"></param>
    /// <param name="height"></param>
    /// <returns></returns>
    public eFinderResult search(PathGridMap grid_map, float start_x, float start_y, float target_x, float target_y, float width, float height)
    {
        if (grid_map == null)
        {
            return(eFinderResult.FAILED);
        }

        eFace8Type walk_dir = eFace8Type.NONE;

        m_cur_grid            = null;
        m_collide_rect.width  = width;
        m_collide_rect.height = height;

        //上一步的位置
        m_last_pos_x = start_x;
        m_last_pos_y = start_y;

        //步长增长方向
        Vector2 pt_step    = Math2DUtils.normalPoint(start_x, start_y, target_x, target_y, STEP_LENGTH);
        float   x_step_inc = pt_step.x;
        float   y_step_inc = pt_step.y;
        //步长个数
        int stepCount = (int)Mathf.Ceil(Math2DUtils.distance(start_x, start_y, target_x, target_y) / STEP_LENGTH);

        //确定移动方向
        float angle = MathUtils.ToDegree(Math2DUtils.LineRadians(start_x, start_y, target_x, target_y));

        walk_dir = (eFace8Type)Math2DUtils.getFace(angle, 8);

        m_cur_grid = grid_map.getNodeByPostion(start_x, start_y);
        if (m_cur_grid == null)
        {
            return(eFinderResult.FAILED);
        }

        //重新调整方向:判断下一步是否可走
        walk_dir = adjustDir(grid_map, walk_dir, start_x + x_step_inc, start_y + y_step_inc);
        switch (walk_dir)
        {
        case eFace8Type.LEFT:
        case eFace8Type.RIGHT:
            y_step_inc = 0;
            break;

        case eFace8Type.UP:
        case eFace8Type.DOWN:
            x_step_inc = 0;
            break;

        case eFace8Type.NONE:
            return(eFinderResult.FAILED);
        }
        //开始寻路,每次移动一个步长
        eFinderResult result = eFinderResult.FAILED;
        int           i      = 1;

        for (i = 1; i <= stepCount; i++)   //从1开始,当前位置不判断
        {
            if (isWalkableRect(grid_map, walk_dir, start_x + x_step_inc * i, start_y + y_step_inc * i))
            {
                m_last_pos_x = start_x + x_step_inc * i;
                m_last_pos_y = start_y + y_step_inc * i;
                result       = eFinderResult.SUCCEEDED;
            }
            else
            {
                //如果第一步都不能走,设置查询失败
                if (i == 1)
                {
                    result = eFinderResult.FAILED;
                }
                else
                {
                    result = eFinderResult.SUCCEEDED_NEAREST;
                }
                break;
            }
        }
        m_target_pos_x = m_last_pos_x;
        m_target_pos_y = m_last_pos_y;

        return(result);
    }