Created
January 14, 2021 12:39
-
-
Save blewert/b4c561d4d0b335b4745868399e80ad87 to your computer and use it in GitHub Desktop.
A simple modular building generator for Unity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @brief A simple modular building generator for Unity. | |
* @author Benjamin Williams | |
*/ | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class SimpleModularBuildingGenerator : MonoBehaviour | |
{ | |
/// <summary> | |
/// A list of building spawnpoints | |
/// </summary> | |
public List<Transform> buildingSpawnpoints; | |
[Header("[prefabs]")] | |
/// <summary> | |
/// The list of bottom prefabs | |
/// </summary> | |
public List<GameObject> bottomPrefabs; | |
/// <summary> | |
/// The list of top prefabs | |
/// </summary> | |
public List<GameObject> topPrefabs; | |
/// <summary> | |
/// The list of mid prefabs | |
/// </summary> | |
public List<GameObject> midPrefabs; | |
[Header("[generation options]")] | |
[Range(1,5)] | |
public int maxMidTiers = 1; | |
/// <summary> | |
/// The roof rotation fix (optional) | |
/// </summary> | |
public Vector3 roofRotationFix; | |
/// <summary> | |
/// Just gives us a random selection from a list | |
/// </summary> | |
/// <param name="collection">The collection</param> | |
/// <returns>A random item</returns> | |
private T RandomChoice<T>(in List<T> collection) => collection[Random.Range(0, collection.Count)]; | |
/// <summary> | |
/// Spawns the top-most tier | |
/// </summary> | |
/// <returns></returns> | |
private GameObject SpawnTopTier(Transform spawn, GameObject lastMidTier) | |
{ | |
//Choose a random prefab | |
var randomTop = this.RandomChoice(in topPrefabs); | |
//Find spawn position | |
var spawnPosition = lastMidTier.transform.position + Vector3.up * lastMidTier.GetComponent<Renderer>().bounds.size.y; | |
//Spawn it | |
var obj = GameObject.Instantiate(randomTop, spawnPosition, spawn.rotation, spawn) as GameObject; | |
//Set the name | |
obj.name = "bottom-section"; | |
//OPTIONAL: Roof rotation fix | |
obj.transform.Rotate(roofRotationFix); | |
//Delete mesh renderer of the parent object so we dont see it (kinda optional) | |
Destroy(spawn.gameObject.GetComponent<Renderer>()); | |
//Return the base | |
return obj; | |
} | |
/// <summary> | |
/// Spawns a random number of mid tiers on top of a base | |
/// </summary> | |
private GameObject SpawnMidTiers(Transform spawn, int numMidTiers, GameObject baseObject) | |
{ | |
//Run from 0 to mid tiers | |
//.. | |
//Set yOffset to base height, initially (we want to spawn on top of the base) | |
float yOffset = baseObject.GetComponent<Renderer>().bounds.size.y; | |
//The last mid tier spawned (for returning) | |
GameObject lastMidTier = baseObject; | |
for(int i = 0; i < numMidTiers; i++) | |
{ | |
//Compute the place to spawn this mid tier: | |
//It's basically just the base position + up * height of building currently | |
var spawnPos = spawn.transform.position + Vector3.up * yOffset; | |
//Choose a prefab | |
var randomPrefab = this.RandomChoice(midPrefabs); | |
//Spawn at this location, set name | |
var obj = GameObject.Instantiate(randomPrefab, spawnPos, baseObject.transform.rotation, spawn); | |
obj.name = $"mid-tier-{i}"; | |
//Add to yOffset the height of this spawned mid tier | |
yOffset += obj.GetComponent<Renderer>().bounds.size.y; | |
//Sete last mid tier to this | |
lastMidTier = obj; | |
} | |
//Return the last mid tier | |
return lastMidTier; | |
} | |
/// <summary> | |
/// Spawns a base at a particular location | |
/// </summary> | |
/// <param name="spawnTransform"></param> | |
private GameObject SpawnBase(Transform spawnTransform) | |
{ | |
//Choose a random prefab | |
var randomBottom = this.RandomChoice(in bottomPrefabs); | |
//Spawn it | |
var obj = GameObject.Instantiate(randomBottom, spawnTransform.position, spawnTransform.rotation, spawnTransform) as GameObject; | |
//Set the name | |
obj.name = "bottom-section"; | |
//Delete mesh renderer of the parent object so we dont see it (kinda optional) | |
Destroy(spawnTransform.gameObject.GetComponent<Renderer>()); | |
//Return the base | |
return obj; | |
} | |
// Start is called before the first frame update | |
void Start() | |
{ | |
foreach(var spawn in buildingSpawnpoints) | |
{ | |
//Spawn the base | |
var baseObject = this.SpawnBase(spawn); | |
//Choose a random amount of mid tiers | |
int numMidTiers = Random.Range(0, maxMidTiers); | |
//And spawn that many | |
var lastMidTier = this.SpawnMidTiers(spawn, numMidTiers, baseObject); | |
//Spawn a roof | |
this.SpawnTopTier(spawn, lastMidTier); | |
} | |
} | |
private float lastTime = 0; | |
public float updateDelta = 0.25f; | |
void Update() | |
{ | |
//Clamp one-sided | |
updateDelta = Mathf.Max(updateDelta, 0.05f); | |
if((Time.time - lastTime) > updateDelta) | |
{ | |
//Set last time | |
lastTime = Time.time; | |
foreach(var spawn in buildingSpawnpoints) | |
{ | |
//Kill all children in building spawn points | |
//.. | |
foreach(Transform child in spawn) | |
Destroy(child.gameObject); | |
//Respawn! | |
//.. | |
//Spawn the base | |
var baseObject = this.SpawnBase(spawn); | |
//Choose a random amount of mid tiers | |
int numMidTiers = Random.Range(0, maxMidTiers); | |
//And spawn that many | |
var lastMidTier = this.SpawnMidTiers(spawn, numMidTiers, baseObject); | |
//Spawn a roof | |
this.SpawnTopTier(spawn, lastMidTier); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment