Ejemplo n.º 1
0
    private GameObject PlaceChurch(AreaData areaData)
    {
        var building2DPolygon = ChurchPrefab.GetComponent <BoxCollider>().Get2DPolygon();
        var border            = areaData.Polygon;

        // Try to place the building on the side of each path
        foreach (var path in areaData.Paths)
        {
            if (path.Any(vtx => !vtx.IsInsidePolygon(areaData.Polygon)))
            {
                continue;
            }

            var pathCenter  = (path[0] + path[1]) / 2f;
            var leftNormal  = (Vector2)Vector3.Cross(path[0] - path[1], Vector3.forward).normalized;
            var rightNormal = -leftNormal;


            float rightAngle = Vector2.SignedAngle(Vector2.up, leftNormal);
            var   rightPoly  = building2DPolygon.Select(vtx => (Vector2)(Quaternion.AngleAxis(rightAngle, Vector3.forward) * vtx) + pathCenter + rightNormal * PathOffset).ToList();

            float leftAngle = Vector2.SignedAngle(Vector2.up, rightNormal);
            var   leftPoly  = building2DPolygon.Select(vtx => (Vector2)(Quaternion.AngleAxis(leftAngle, Vector3.forward) * vtx) + pathCenter + leftNormal * PathOffset).ToList();

            Vector2 leftCenter  = leftPoly.GetPolygonCenter();
            Vector2 rightCenter = rightPoly.GetPolygonCenter();

            // Try right side placement
            bool rightInvalid = rightPoly.Any(vtx => !vtx.IsInsidePolygon(border)) ||
                                ClearPolygons.Any(clearPoly => rightPoly.Any(vtx => vtx.IsInsidePolygon(clearPoly)) ||
                                                  clearPoly.Any(vtx => vtx.IsInsidePolygon(rightPoly)) ||
                                                  rightCenter.IsInsidePolygon(clearPoly) ||
                                                  clearPoly.GetPolygonCenter().IsInsidePolygon(rightPoly));

            if (!rightInvalid)
            {
                ClearPolygons.Add(rightPoly.ToArray());
                var position2D = pathCenter + rightNormal * PathOffset;
                var position   = new Vector3(position2D.x, 0, position2D.y);
                var rotation   = Quaternion.LookRotation(new Vector3(pathCenter.x, 0, pathCenter.y) - position,
                                                         Vector3.up);
                var go = Object.Instantiate(ChurchPrefab, position, rotation);
                return(go);
            }

            // Try left side placement
            bool leftInvalid = leftPoly.Any(vtx => !vtx.IsInsidePolygon(border)) ||
                               ClearPolygons.Any(clearPoly => leftPoly.Any(vtx => vtx.IsInsidePolygon(clearPoly)) ||
                                                 clearPoly.Any(vtx => vtx.IsInsidePolygon(leftPoly) ||
                                                               leftCenter.IsInsidePolygon(clearPoly)) ||
                                                 clearPoly.GetPolygonCenter().IsInsidePolygon(leftPoly));

            if (!leftInvalid)
            {
                ClearPolygons.Add(leftPoly.ToArray());
                var position2D = pathCenter + leftNormal * PathOffset;
                var position   = new Vector3(position2D.x, 0, position2D.y);
                var rotation   = Quaternion.LookRotation(new Vector3(pathCenter.x, 0, pathCenter.y) - position,
                                                         Vector3.up);
                var go = Object.Instantiate(ChurchPrefab, position, rotation);
                return(go);
            }
        }

        return(null);
    }
Ejemplo n.º 2
0
    private List <Vector2[]> GetValidRectangles(AreaData areaData)
    {
        var result = new List <Vector2[]>();
        var count  = 0;

        do
        {
            var     fitPossible = false;
            Vector2 topLeft     = Vector2.zero;
            Vector2 bottomRight = Vector2.zero;
            Vector2 topRight    = Vector2.zero;
            Vector2 bottomLeft  = Vector2.zero;
            Vector2 up          = Vector2.zero;
            Vector2 left        = Vector2.zero;

            // Find a suitable start point for the rectangle
            bool wasRight = false;
            foreach (var path in areaData.Paths)
            {
                if (path.Any(vtx => !vtx.IsInsidePolygon(areaData.Polygon)))
                {
                    continue;
                }

                Vector2 pathCenter  = (path[0] + path[1]) / 2f;
                Vector2 leftNormal  = Vector3.Cross(path[0] - path[1], Vector3.forward).normalized;
                Vector2 rightNormal = -leftNormal;
                float   offset      = (PathOffset + 3);

                // Try right side placement
                bottomRight = pathCenter + rightNormal * offset;
                bool rightInvalid = ClearPolygons.Any(poly => bottomRight.IsInsidePolygon(poly));
                if (!rightInvalid)
                {
                    up       = rightNormal;
                    left     = Vector3.Cross(leftNormal, Vector3.forward).normalized;
                    wasRight = true;
                    break;
                }

                // Try left side placement
                bottomRight = pathCenter + leftNormal * offset;
                bool leftInvalid = ClearPolygons.Any(poly => bottomRight.IsInsidePolygon(poly));
                if (!leftInvalid)
                {
                    up   = leftNormal;
                    left = Vector3.Cross(leftNormal, Vector3.forward).normalized;
                    break;
                }

                bottomRight = Vector2.zero;
            }

            // Early break if previous search failed
            if (up == Vector2.zero || left == Vector2.zero)
            {
                break;
            }

            // Expand until not possible anymore in both directions
            bottomRight = bottomRight - up * 2 - left * 2;
            topLeft     = bottomRight;
            topRight    = bottomRight;
            bottomLeft  = bottomRight;
            bool expandLeft, expandUp;
            do
            {
                expandLeft = false;
                expandUp   = false;

                // Expand left and check
                topLeft    += left;
                bottomLeft += left;
                if (!ClearPolygons.Any(poly => topLeft.IsInsidePolygon(poly)) &&
                    !ClearPolygons.Any(poly => bottomLeft.IsInsidePolygon(poly)) &&
                    topLeft.IsInsidePolygon(areaData.Polygon) &&
                    bottomLeft.IsInsidePolygon(areaData.Polygon))
                {
                    expandLeft  = true;
                    fitPossible = true;
                }
                else
                {
                    topLeft    -= left;
                    bottomLeft -= left;
                }

                // Expand right and check
                topLeft  += up;
                topRight += up;
                if (!ClearPolygons.Any(poly => topLeft.IsInsidePolygon(poly)) &&
                    !ClearPolygons.Any(poly => topRight.IsInsidePolygon(poly)) &&
                    topLeft.IsInsidePolygon(areaData.Polygon) &&
                    topRight.IsInsidePolygon(areaData.Polygon))
                {
                    expandUp    = true;
                    fitPossible = true;
                }
                else
                {
                    topLeft  -= up;
                    topRight -= up;
                }
            } while (expandLeft || expandUp);

            // LOOP CONDITION BREAK
            if (!fitPossible)
            {
                break;
            }

            float upGuard   = 4;
            var   rectangle = new[] { bottomRight, bottomLeft, topLeft - up * upGuard, topRight - up * upGuard };
            result.Add(rectangle);
            if (wasRight)
            {
                ClearPolygons.Add(rectangle.OffsetToCenter(rectangle.GetPolygonCenter(), -10).ToArray());
            }
            else
            {
                var sortedRectangle = rectangle.OffsetToCenter(rectangle.GetPolygonCenter(), -10).ToList();
                sortedRectangle.SortVertices(sortedRectangle.GetPolygonCenter());
                ClearPolygons.Add(sortedRectangle.ToArray());
            }
            count++;
        } while (count < 5); // INFINITE LOOP SAFE GUARD

        return(result);
    }