示例#1
0
    Vector2 GetDirection(Vector2 start, StreetLine toAvoid)
    {
        //this version doesn't check for heading to Vector2.zero,
        //because it has to check for toAvoid
        if (GS.RChance(diagonalChance))
        {
            Vector2 result = diags.RandomElement();
            while (Mathf.Abs(Vector2.Dot(result, (toAvoid.A - toAvoid.B).normalized)) > 0.5)
            {
                result = diags.RandomElement();
            }
            return(result);
        }

        List <Vector2> options = new List <Vector2>();

        for (int i = 0; i < GS.CardinalDirs.Count; i++)
        {
            float dot = (toAvoid != null) ? Vector2.Dot(GS.CardinalDirs[i], (toAvoid.B - toAvoid.A).normalized) : 0;
            if (Mathf.Abs(dot) < 0.1f)
            {
                options.Add(GS.CardinalDirs[i]);
            }
        }
        return(options.RandomElement());
    }
示例#2
0
    IntersectionPoint SplitStreetLine(StreetLine line, Vector2 point)
    {
        //replaces line with 2 lines with one shared intersection
        placed.Remove(line);
        IntersectionPoint inter = new IntersectionPoint(point);

        placed.Add((line.AOnRim) ? new StreetLine(line.A, inter) : new StreetLine(line.InterPointA, inter));
        placed.Add((line.BOnRim) ? new StreetLine(inter, line.B) : new StreetLine(inter, line.InterPointB));
        return(inter);
    }
示例#3
0
    void PlaceStreetLine(Vector2 start, Vector2 end, StreetLine intersectedAtStart, StreetLine intersectedAtEnd)
    {
        IntersectionPoint interStart;
        IntersectionPoint interEnd;

        if (intersectedAtStart != null)
        {
            if (intersectedAtStart.A == start && !intersectedAtStart.AOnRim)
            {
                interStart = intersectedAtStart.InterPointA;
            }
            else if (intersectedAtStart.B == start && !intersectedAtStart.BOnRim)
            {
                interStart = intersectedAtStart.InterPointB;
            }
            else
            {
                //the StreetLine intersected at start of the line-to-be has not been split yet,
                //so we need to split it
                interStart = SplitStreetLine(intersectedAtStart, start);
            }

            if (intersectedAtEnd != null)
            {
                interEnd = SplitStreetLine(intersectedAtEnd, end);
                placed.Add(new StreetLine(interStart, interEnd));
            }
            else
            {
                placed.Add(new StreetLine(interStart, end));
            }
        }
        else if (intersectedAtEnd != null)
        {
            interEnd = SplitStreetLine(intersectedAtEnd, end);
            placed.Add(new StreetLine(start, interEnd));
        }
        else
        {
            placed.Add(new StreetLine(start, end));
        }
    }
示例#4
0
    IEnumerator Generate()
    {
        yield return(StartCoroutine(lineGen.GenStreetLines()));

        yield return(StartCoroutine(lineGen.FillIntersectionPointConnections()));

        List <StreetLine>        streetLines = lineGen.GetPlaced();
        List <IntersectionPoint> interPoints = lineGen.GetPlacedInterPoints();

        diagnostics.CheckIfIntersectionPointsOverlap(interPoints);
        yield return(StartCoroutine(lineExpander.ExpandStreetLines(streetLines, interPoints)));

        //diagnostics.DebugDrawStreetLineCorners(streetLines, 300f);
        List <Intersection> intersections = lineVerticalizer.ConvertIntersectionPointsToIntersections(interPoints);
        List <Street>       streets       = lineVerticalizer.ConvertStreetLinesToStreets(streetLines);

        for (int i = 0; i < intersections.Count; i++)
        {
            intersections[i].ExtractConnected();
        }
        yield return(StartCoroutine(streetMeshGen.GenerateIntersectionMeshes(intersections)));

        yield return(StartCoroutine(streetMeshGen.GenerateStreetMeshes(streets)));

        List <RimStreetLine> streetLinesOnRim = StreetLine.ExtractRimStreetLines(streetLines);

        yield return(StartCoroutine(cityBlockGen.ExtractCityBlocks(intersections, streetLinesOnRim)));

        yield return(StartCoroutine(cityBlockGen.GenerateCityBlockTerrainMeshes()));

        //List<CityBlock> blocks = cityBlockGen.Blocks;
        //cityBlockPurposeDeterminer.DeterminePurposeOfCityBlocks(blocks);
        //for (int i = 0; i < blocks.Count; i++)
        //{
        //    if (cityBlockContentGenerators.ContainsKey(blocks[i].Purpose))
        //    {
        //        yield return StartCoroutine(cityBlockContentGenerators[blocks[i].Purpose].Generate(blocks[i]));
        //    }
        //}

        FinalizeGeneration();
    }
示例#5
0
    public IEnumerator GenStreetLines()
    {
        DB.Log("GENERATING STREET LINES", 1);
        //to keep track of how many streets we create we need a seperate variable,
        //since placed.Count doesn't reflect the same thing - 1 whole street can be
        //comprised of many StreetLine objects one after the other with intersections in between
        //That's because a SreetLine obj represents a street from intersection to intersection,
        //but in terms of count we care more about those long continous streets
        int   wholeStreetsCount = 0;
        int   tries             = 0;
        float rayRange          = rimRadius * 2.1f;

        while (wholeStreetsCount < desiredStreetCount)
        {
            tries += 1;
            bool       genFromExisting = (placed.Count >= thresholdForGeneratingFromExistingLines && GS.RChance(generateFromExistingChance));
            Vector2    start, dir;
            StreetLine existingStartLine = null;
            if (genFromExisting)
            {
                existingStartLine = placed.RandomElement();
                start             = Vector2.Lerp(existingStartLine.A, existingStartLine.B, Random.Range(0.15f, 0.85f));
                dir = GetDirection(start, existingStartLine);
            }
            else
            {
                start = GS.ROnUnitCircle(rimRadius);
                dir   = GetDirection(start);
            }

            RaycastHit hit;
            Ray        ray = new Ray(start.ShiftToV3() + dir.ShiftToV3() * rayRange, -dir.ShiftToV3());
            //this raycast has to be reversed because they dont work from within colliders
            if (!Physics.Raycast(ray, out hit, rayRange, maskRimSphere, QueryTriggerInteraction.Collide))
            {
                continue; //this should never happen, the raycast is set up to always hit
            }

            Vector2 end = hit.point.UnShiftToV2(); //end of the whole street
            List <StreetLineIntersectionResult> potentiallyCrossed = GetIntersectWithStreetLineResults(start, end, placed, existingStartLine);

            //propagating the whole street forward
            bool placedAtLeastOne = false;
            for (int i = 0; i <= potentiallyCrossed.Count; i++) //mind the <=
            {
                Vector2 streetLineStart = (i == 0) ? start : potentiallyCrossed[i - 1].intersection;
                Vector2 streetLineEnd   = (i == potentiallyCrossed.Count) ? end : potentiallyCrossed[i].intersection;
                if (streetLineStart == streetLineEnd)
                {
                    DB.Log("StreetLine start and end are same.");
                }
                //DB.Log($"streetLineStart: {streetLineStart} | streetLineEnd: {streetLineEnd} | dir: {dir} | i: {i}/{potentiallyCrossed.Count}");
                if (Vector2.Distance(streetLineStart, streetLineEnd) < minSeparation)
                {
                    //if the distance is smaller than min separation, it means the potential streetline encounters
                    //another street line and crosses it very near from start point, which would make it difficult later
                    //for placing intersection meshes
                    //we also need a separate check for this, because the regular separation check only takes
                    //into account separation with lines that are nearly paralell
                    //DB.Log("Length too small");
                    break;
                }
                if (!PotentialLineHasCorrectSeparation(streetLineStart, streetLineEnd, placed))
                {
                    //we need to check if this potential line isn't to close to other lines that are running nearly paralel to it
                    //to prevent creating narrow city blocks
                    //DB.Log("Separation not correct.");
                    break;
                }
                StreetLine lineOnStart = null;
                if (genFromExisting && i == 0)
                {
                    lineOnStart = existingStartLine;
                }
                else if (i > 0)
                {
                    lineOnStart = FindStreetLineWithIntersectionAtPoint(streetLineStart, placed);
                    if (lineOnStart == null)
                    {
                        DB.Error("line on start is null");
                    }
                }
                StreetLine lineOnEnd = (i == potentiallyCrossed.Count) ? null : potentiallyCrossed[i].line;
                PlaceStreetLine(streetLineStart, streetLineEnd, lineOnStart, lineOnEnd);
                placedAtLeastOne = true;
                placed.Last().DebugDraw(300f);
                //yield return new WaitForSeconds(2.5f);
                if (!GS.RChance(propagateChance))
                {
                    break;
                }
            }
            if (placedAtLeastOne)
            {
                tries              = 0;
                wholeStreetsCount += 1;
            }
            yield return(null);

            if (tries == maxTriesPerLine) //safety feature
            {
                tries = 0;
                desiredStreetCount -= 1;
                DB.Log("Max tries reached.");
            }
        }
    }
示例#6
0
 public StreetLineIntersectionResult(StreetLine line, Vector2 intersection)
 {
     this.line         = line;
     this.intersection = intersection;
 }
示例#7
0
    List <StreetLineIntersectionResult> GetIntersectWithStreetLineResults(Vector2 start, Vector2 end, List <StreetLine> options, StreetLine ignored)
    {
        List <StreetLineIntersectionResult> intersectionResults = new List <StreetLineIntersectionResult>();
        Vector2 intersection;

        for (int i = 0; i < options.Count; i++)
        {
            if (ignored != null && ignored == options[i])
            {
                continue;
            }
            if (GeoMath.LineSegmentsIntersect(start, end, options[i].A, options[i].B, out intersection))
            {
                intersectionResults.Add(new StreetLineIntersectionResult(options[i], intersection));
            }
        }

        intersectionResults.Sort((a, b) => (Vector2.SqrMagnitude(start - a.intersection) < Vector2.SqrMagnitude(start - b.intersection)) ? -1 : 1);
        return(intersectionResults);
    }
示例#8
0
 public RimStreetLine(StreetLine line, bool calcAngleFromA)
 {
     Line = line;
     AngularPosCalculatedFromA = calcAngleFromA;
     AngularPosOnRim           = (calcAngleFromA) ? -Vector2.SignedAngle(-Vector2.up, Line.A) : -Vector2.SignedAngle(-Vector2.up, Line.B);
 }
示例#9
0
 public RimStreetLine(StreetLine line)
 {
     Line = line;
     AngularPosCalculatedFromA = (Line.AOnRim);
     AngularPosOnRim           = (Line.AOnRim) ? -Vector2.SignedAngle(-Vector2.up, Line.A) : -Vector2.SignedAngle(-Vector2.up, Line.B);
 }
示例#10
0
    public void CreateCornersForConnected()
    {
        //DB.Log($"Creating corners for Connected (ConnectingStreetLines.Count: {Connected.Count}).");
        if (Connected.Count < 3 || Connected.Count > 4)
        {
            return;
        }

        for (int i = 0; i < Connected.Count; i++)
        {
            for (int o = 0; o < Connected.Count; o++)
            {
                if (o == i)
                {
                    continue;
                }
                //we do this to ensure that those dirs are dirs pointing away from this intersection point and not directly towards it
                Vector2 iDir = (this == Connected[i].InterPointA) ? Connected[i].B - Connected[i].A : Connected[i].A - Connected[i].B;
                Vector2 oDir = (this == Connected[o].InterPointA) ? Connected[o].B - Connected[o].A : Connected[o].A - Connected[o].B;
                iDir = iDir.normalized;
                oDir = oDir.normalized;
                if (iDir.SameOrOppositeDir(oDir, 0.01f) && Connected.Count == 3)
                {
                    //connected are basically continuations of each other, so the corners are in a direction
                    //that is exactly half way between each of them and a line perpendicular to them,
                    //       x\ | /x
                    //  [i]____\|/____[o]
                    //
                    //but there are of course two perpendicular lines we could pick from, so we check which one doesn't interfere with other
                    //Connected StreetLines, we will always find one that doesn't, because this scenario assumes Connected.Count == 3
                    Vector2    perp1 = Vector2.Perpendicular(iDir);
                    Vector2    perp2 = -Vector2.Perpendicular(iDir);
                    StreetLine onlyOtherConnected = null;
                    for (int p = 0; p < Connected.Count; p++)
                    {
                        if (p != o && p != i)
                        {
                            onlyOtherConnected = Connected[p]; break;
                        }
                    }
                    //we do this to ensure this dir is the one that points away from this intersection point, not straight towards it
                    Vector2 otherDir = (this == onlyOtherConnected.InterPointA) ? onlyOtherConnected.B - onlyOtherConnected.A : onlyOtherConnected.A - onlyOtherConnected.B;
                    otherDir = otherDir.normalized;
                    float   angle1     = Vector2.Angle(perp1, otherDir);
                    float   angle2     = Vector2.Angle(perp2, otherDir);
                    Vector2 pickedPerp = (angle1 > angle2) ? perp1 : perp2;
                    Vector2 oCorner    = Position + (pickedPerp + oDir) * Connected[o].VirtualWidth * 0.5f;
                    Vector2 iCorner    = Position + (pickedPerp + iDir) * Connected[i].VirtualWidth * 0.5f;
                    AddCornerIfAbsent(oCorner);
                    AddCornerIfAbsent(iCorner);
                    Connected[i].AddCornerIfAbsent(iCorner);
                    Connected[o].AddCornerIfAbsent(oCorner);
                }
                else if (!iDir.SameOrOppositeDir(oDir, 0.01f))
                {
                    Vector2 corner = Position + (iDir * Connected[o].VirtualWidth + oDir * Connected[i].VirtualWidth) * 0.5f;
                    AddCornerIfAbsent(corner);
                    Connected[i].AddCornerIfAbsent(corner);
                    Connected[o].AddCornerIfAbsent(corner);
                }
            }
        }

        if (Corners.Count != 4)
        {
            DB.Error("Invalid number of Corners in IntersectionPoint.");
            //Debug.DrawRay(Position.ShiftToV3(), Vector3.up * 30f, Color.magenta, 300f);
        }
    }