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); }
/// <summary> /// 设置朝向 /// </summary> /// <param name="dir">忽视z轴</param> public override void SetForward(Vector3 dir) { //转换成角度 float angle = Math2DUtils.Point2Radians(dir.x, dir.y); this.SetRotate2D(angle); }
/// <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(); }
/// <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); }