Ejemplo n.º 1
0
        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()));
        }
Ejemplo n.º 2
0
        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);
        }