File size: 4,329 Bytes
6cae93f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using UnityEngine;

namespace UnityAgent
{
    /// <summary>
    /// Procedural city generator: spawns a grid of buildings of varying
    /// heights with emissive windows, street lights and parked vehicles.
    /// Designed to be paired with <see cref="RoadNetwork"/>.
    /// </summary>
    public class CityGenerator : MonoBehaviour
    {
        [Header("Grid")]
        public int gridX = 8;
        public int gridZ = 8;
        public float blockSpacing = 30f;

        [Header("Buildings")]
        public int buildingsPerBlock = 1;
        public float minBuildingHeight = 8f;
        public float maxBuildingHeight = 40f;
        public float buildingFootprint = 8f;
        public Color wallColor = new Color(0.4f, 0.4f, 0.42f);
        public Color windowColor = new Color(1.0f, 0.85f, 0.4f);

        [Header("Street Lights")]
        public bool spawnStreetLights = true;
        public float lightSpacing = 15f;
        public Color lightColor = new Color(1.0f, 0.85f, 0.5f);
        public float lightIntensity = 1.5f;
        public float lightRange = 15f;

        private readonly System.Collections.Generic.List<Light> _lights = new System.Collections.Generic.List<Light>();

        private void Start()
        {
            Generate();
        }

        public void Generate()
        {
            Material wallMat = BuildingGenerator.MakeWallMaterial(wallColor);
            Material winMat = BuildingGenerator.MakeWindowMaterial(windowColor);

            float totalX = (gridX - 1) * blockSpacing;
            float totalZ = (gridZ - 1) * blockSpacing;
            Vector3 origin = transform.position - new Vector3(totalX * 0.5f, 0f, totalZ * 0.5f);

            for (int x = 0; x < gridX; x++)
            {
                for (int z = 0; z < gridZ; z++)
                {
                    Vector3 block = new Vector3(origin.x + x * blockSpacing, 0f, origin.z + z * blockSpacing);
                    SpawnBlock(block, wallMat, winMat);
                }
            }

            if (spawnStreetLights) SpawnStreetLights(origin, totalX, totalZ);
        }

        private void SpawnBlock(Vector3 center, Material wallMat, Material winMat)
        {
            for (int i = 0; i < buildingsPerBlock; i++)
            {
                float h = Random.Range(minBuildingHeight, maxBuildingHeight);
                Vector3 size = new Vector3(buildingFootprint, h, buildingFootprint);
                Vector3 pos = center + new Vector3(
                    Random.Range(-4f, 4f), 0f, Random.Range(-4f, 4f));
                BuildingGenerator.Generate($"Building_{center.x}_{center.z}_{i}", pos, size, wallMat, winMat);
            }
        }

        private void SpawnStreetLights(Vector3 origin, float totalX, float totalZ)
        {
            Material poleMat = BuildingGenerator.MakeWallMaterial(new Color(0.1f, 0.1f, 0.1f));

            for (float x = origin.x; x <= origin.x + totalX + 0.1f; x += lightSpacing)
            {
                for (float z = origin.z; z <= origin.z + totalZ + 0.1f; z += lightSpacing)
                {
                    SpawnStreetLight(new Vector3(x, 0f, z), poleMat);
                }
            }
        }

        private void SpawnStreetLight(Vector3 pos, Material poleMat)
        {
            GameObject pole = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
            pole.name = "StreetLight";
            pole.transform.SetParent(transform, false);
            pole.transform.position = pos + Vector3.up * 4f;
            pole.transform.localScale = new Vector3(0.2f, 4f, 0.2f);
            pole.GetComponent<MeshRenderer>().sharedMaterial = poleMat;

            GameObject bulb = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            bulb.transform.SetParent(pole.transform, false);
            bulb.transform.localPosition = Vector3.up * 0.9f;
            bulb.transform.localScale = Vector3.one * 0.4f;
            bulb.GetComponent<MeshRenderer>().sharedMaterial = BuildingGenerator.MakeWindowMaterial(lightColor);

            Light l = bulb.AddComponent<Light>();
            l.type = LightType.Point;
            l.color = lightColor;
            l.intensity = lightIntensity;
            l.range = lightRange;
            _lights.Add(l);
        }

        public Light[] StreetLights => _lights.ToArray();
    }
}