public IEnumerator generate(string seed) { // initalize random state by the hash code of seed Random.InitState(seed.GetHashCode()); int roadCount = 0; // population density for global goals // ------------------------------TEST--------------------------------- perlin = new SimulatedParaMap( paraMaps.Width, paraMaps.Height, null, Random.Range(-99999f, 99999f), Random.Range(-99999f, 99999f)); // ------------------------------TEST--------------------------------- #if UNITY_EDITOR System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); #endif //UNITY_EDITOR // priority queue var priQueue = new IntervalHeap <RoadSegment <MetaInformation> >(); // first road segment Vector2 centre = (maxMapPostion + minMapPostion) * .5f; var centre3 = new Junction(centre.x, 0, centre.y); Road rootRoad = new Road( centre3, new Vector3(centre.x + Config.HIGHWAY_DEFAULT_LENGTH, 0, centre.y), Config.HIGHWAY_DEFAULT_WIDTH); MetaInformation meta = new HighwayMetaInfo(); var rootSegment = new RoadSegment <MetaInformation>(0, rootRoad, meta); priQueue.Add(rootSegment); rootRoad = new Road( centre3, new Vector3(centre.x - Config.HIGHWAY_DEFAULT_LENGTH, 0, centre.y), Config.HIGHWAY_DEFAULT_WIDTH); meta = new HighwayMetaInfo(); rootSegment = new RoadSegment <MetaInformation>(0, rootRoad, meta); priQueue.Add(rootSegment); // loop until priority queue to empty while (priQueue.Count > 0 && map.Roads.Count < Config.ROAD_COUNT_LIMIT) { // pop smallest road from priority queue RoadSegment <MetaInformation> minSeg = priQueue.DeleteMin(); // check that it is valid, skip to the next segment if it is not if (localConstraints != null) { if (!localConstraints(ref minSeg)) { if (minSeg.discarded) { foreach (var road in minSeg.roads) { map.deleteRoad(road); } } continue; } } // It's valid, so add it to list. It is now part of the final result map.insertRoad(minSeg.getLastRoad()); // produce potential segments leading off this road according to some global goal List <RoadSegment <MetaInformation> > pendingSegs = null; if (globalGoals != null && !minSeg.successionBlocked) { globalGoals(minSeg, out pendingSegs); foreach (RoadSegment <MetaInformation> seg in pendingSegs) { if (seg.metaInformation.Type.Equals("Highway")) { seg.timeDelay += minSeg.timeDelay; } else if (seg.metaInformation.Type.Equals("Street")) { seg.timeDelay += minSeg.timeDelay + priQueue.Count; } priQueue.Add(seg); } } ++roadCount; if (roadCount >= Config.ROAD_COUNT_PER_FRAME) { roadCount = 0; yield return(null); } } #if UNITY_EDITOR stopwatch.Stop(); Debug.Log("Road counts: " + map.Roads.Count); Debug.Log("Junction counts: " + map.Junctions.Count); Debug.Log("Time on generating roadmap: " + stopwatch.ElapsedMilliseconds); debug_drawBlocks = true; #endif //UNITY_EDITOR yield return(StartCoroutine(constructRoads())); }
protected bool makeHighwaysByPopulationDensity( RoadSegment <MetaInformation> approvedSeg, List <RoadSegment <MetaInformation> > potentialSegs) { // Vaialble declarations bool highwayBranchAppeared = false; var pendingBranchSegs = new List <RoadSegment <MetaInformation> >(); float branchDigreeDiff = 0f; // If segment grows beyond the fixed length, // several branches will appear. if (approvedSeg.TotalLength >= Config.HIGHWAY_SEGMENT_MAX_LENGTH) { highwayBranchAppeared = true; } // growth segment will grow along last segment. var pendingGrowthSegs = new List <RoadSegment <MetaInformation> >(); float growthDigreeDiff = Config.HIGHWAY_GROWTH_MAX_DEGREE - Config.HIGHWAY_GROWTH_MIN_DEGREE; // branch segment will make a branch from the end. if (highwayBranchAppeared) { branchDigreeDiff = Config.HIGHWAY_BRANCH_MAX_DEGREE - Config.HIGHWAY_BRANCH_MIN_DEGREE; } else { branchDigreeDiff = Config.STREET_BRANCH_MAX_DEGREE - Config.STREET_BRANCH_MIN_DEGREE; } Road approvedRoad = approvedSeg.getLastRoad(); for (int i = 0; i < 4; ++i) { // get a growth digree randomly float growthDigree = Random.Range(-growthDigreeDiff, growthDigreeDiff); growthDigree += (growthDigree > 0) ? Config.HIGHWAY_GROWTH_MIN_DEGREE : -Config.HIGHWAY_GROWTH_MIN_DEGREE; // figure out the end point of new road var rotation = Quaternion.Euler(0, growthDigree, 0); var potentialRoadEnd = approvedRoad.end.position + rotation * approvedRoad.Direction.normalized * Config.HIGHWAY_DEFAULT_LENGTH; // create new road var potentialRoad = new Road(approvedRoad.end, potentialRoadEnd, Config.HIGHWAY_DEFAULT_WIDTH); var metaInfo = new HighwayMetaInfo(); metaInfo.populationDensity = perlin.getValue(potentialRoadEnd.x, potentialRoadEnd.z); var potentialSeg = new RoadSegment <MetaInformation>(0, potentialRoad, metaInfo); pendingGrowthSegs.Add(potentialSeg); if (highwayBranchAppeared) { // get a branch digree randomly float branchDigree = Random.Range(-branchDigreeDiff, branchDigreeDiff); branchDigree += (branchDigree > 0) ? Config.HIGHWAY_BRANCH_MIN_DEGREE : -Config.HIGHWAY_BRANCH_MIN_DEGREE; // figure out the end point of new branch road rotation = Quaternion.Euler(0, branchDigree, 0); potentialRoadEnd = approvedRoad.end.position + rotation * approvedRoad.Direction.normalized * Config.HIGHWAY_DEFAULT_LENGTH; // create new branch road potentialRoad = new Road(approvedRoad.end, potentialRoadEnd, Config.HIGHWAY_DEFAULT_WIDTH); metaInfo = new HighwayMetaInfo(); metaInfo.populationDensity = perlin.getValue(potentialRoadEnd.x, potentialRoadEnd.z); potentialSeg = new RoadSegment <MetaInformation>(0, potentialRoad, metaInfo); pendingBranchSegs.Add(potentialSeg); } else { // get a branch digree randomly float branchDigree = Random.Range(-branchDigreeDiff, branchDigreeDiff); branchDigree += (branchDigree > 0) ? Config.STREET_BRANCH_MIN_DEGREE : -Config.STREET_BRANCH_MIN_DEGREE; // figure out the end point of new branch road rotation = Quaternion.Euler(0, branchDigree, 0); potentialRoadEnd = approvedRoad.end.position + rotation * approvedRoad.Direction.normalized * Config.STREET_DEFAULT_LENGTH; // create new branch road // appears where people live only var populationDensity = perlin.getValue(potentialRoadEnd.x, potentialRoadEnd.z); if (populationDensity > Config.MIN_POPULATION_DENSITY_VALUE + 0.15f) { potentialRoad = new Road(approvedRoad.end, potentialRoadEnd, Config.STREET_DEFAULT_WIDTH); var streetMetaInfo = new StreetMetaInfo(); streetMetaInfo.populationDensity = populationDensity; potentialSeg = new RoadSegment <MetaInformation>(0, potentialRoad, streetMetaInfo); pendingBranchSegs.Add(potentialSeg); } } } // pick out the road where has the most population density var maxDensityGrowthRoad = pendingGrowthSegs .OrderByDescending(x => ((HighwayMetaInfo)x.metaInformation).populationDensity) .FirstOrDefault(); if (highwayBranchAppeared) { var maxDensityBranchRoad = pendingBranchSegs .OrderByDescending(x => ((HighwayMetaInfo)x.metaInformation).populationDensity) .Take(1); // as for growth road, add it to result directly potentialSegs.Add(maxDensityGrowthRoad); // as for branch road, add if it has higher population density var growthRoadDensity = ((HighwayMetaInfo)maxDensityGrowthRoad.metaInformation).populationDensity; foreach (var road in maxDensityBranchRoad) { if (((HighwayMetaInfo)road.metaInformation).populationDensity > growthRoadDensity) { potentialSegs.Add(road); } else { break; } } } else { var maxDensityBranchRoad = pendingBranchSegs .OrderByDescending(x => ((StreetMetaInfo)x.metaInformation).populationDensity) .Take(1); // segment grows approvedSeg.grow(maxDensityGrowthRoad.getLastRoad()); approvedSeg.metaInformation = maxDensityGrowthRoad.metaInformation; potentialSegs.Add(approvedSeg); // add the street potentialSegs.AddRange(maxDensityBranchRoad); } return(potentialSegs.Count > 0); }