using UnityEngine; namespace UnityAgent { /// /// Procedural city generator: spawns a grid of buildings of varying /// heights with emissive windows, street lights and parked vehicles. /// Designed to be paired with . /// 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 _lights = new System.Collections.Generic.List(); 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().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().sharedMaterial = BuildingGenerator.MakeWindowMaterial(lightColor); Light l = bulb.AddComponent(); l.type = LightType.Point; l.color = lightColor; l.intensity = lightIntensity; l.range = lightRange; _lights.Add(l); } public Light[] StreetLights => _lights.ToArray(); } }