Created
August 7, 2019 20:30
-
-
Save tudddorrr/460a28e8e0c82c5cdb5a36b8acb5eab8 to your computer and use it in GitHub Desktop.
Crawle 2 - WorldGen v1.0
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
| using UnityEngine; | |
| using Photon.Pun; | |
| using System.Collections.Generic; | |
| using Pathfinding; | |
| using System.Linq; | |
| using ExitGames.Client.Photon; | |
| public class WorldGenerator : MonoBehaviour { | |
| public static System.Random rng, masterRng; | |
| public static float worldSize; | |
| readonly int | |
| maxDirt = 800, | |
| maxTallGrass = 800, | |
| maxDecals = 1500, | |
| maxFruitBushes = 1000, | |
| maxForests = 10, | |
| maxTrees = 750, | |
| maxRockBiomes = 30, | |
| maxOreNodes = 300, | |
| maxSwamps = 3, | |
| maxSwampGrass = 1000, | |
| maxSwampRivers = 2, | |
| maxRivers = 10, | |
| maxAmbientSounds = 200, | |
| maxBranches = 200, | |
| maxRocks = 200, | |
| maxAnimals = 150; | |
| // Biomes | |
| public static Rect[] swampBounds; | |
| // Colliders | |
| public static List<Collider2D> colliders = new List<Collider2D>(); | |
| // Resources | |
| GameObject dirt, tallGrass, fruitBush, oreNode, decal, swampGrass, riverSeeker, water; | |
| GameObject[] trees, ambience; | |
| public void Start() { | |
| worldSize = GameObject.Find("Grass").GetComponent<SpriteRenderer>().size.x; | |
| // Load resources | |
| dirt = Resources.Load("WorldObjects/Dirt") as GameObject; | |
| tallGrass = Resources.Load("WorldObjects/TallGrass") as GameObject; | |
| fruitBush = Resources.Load("WorldObjects/FruitBush") as GameObject; | |
| oreNode = Resources.Load("WorldObjects/OreNode") as GameObject; | |
| decal = Resources.Load("WorldObjects/Decal") as GameObject; | |
| swampGrass = Resources.Load("WorldObjects/SwampGrass") as GameObject; | |
| riverSeeker = Resources.Load("WorldObjects/RiverSeeker") as GameObject; | |
| water = Resources.Load("WorldObjects/Water") as GameObject; | |
| trees = new GameObject[] { Resources.Load("WorldObjects/Trees/Birch") as GameObject, Resources.Load("WorldObjects/Trees/Oak") as GameObject, Resources.Load("WorldObjects/Trees/Willow") as GameObject }; | |
| ambience = new GameObject[] { Resources.Load("Sounds/Birds Ambience") as GameObject, Resources.Load("Sounds/Cicadas Ambience") as GameObject }; | |
| } | |
| public void Generate() { | |
| int seed; | |
| if(PhotonNetwork.IsMasterClient) { | |
| string sDate = System.DateTime.Now.ToUniversalTime().ToString(); | |
| System.DateTime datevalue = System.Convert.ToDateTime(sDate); | |
| seed = (datevalue.DayOfYear + 1) * (datevalue.Minute + 1); | |
| Hashtable hash = new Hashtable { | |
| { "SEED", seed } | |
| }; | |
| PhotonNetwork.CurrentRoom.SetCustomProperties(hash); | |
| } else { | |
| seed = (int) PhotonNetwork.CurrentRoom.CustomProperties["SEED"]; | |
| } | |
| rng = new System.Random(seed); | |
| masterRng = new System.Random(seed); | |
| // Non-networked | |
| GenSwamps(); | |
| GenTallGrass(); | |
| GenDecals(); | |
| GenAmbientSounds(); | |
| if(PhotonNetwork.IsMasterClient) { | |
| // Networked, unmanaged | |
| GenWorldItems(); | |
| GenAnimals(); | |
| // Networked, managed | |
| GenTrees(); | |
| GenOreNodes(); | |
| GenDirt(); | |
| GenFruitBushes(); | |
| GenRivers(); | |
| } | |
| } | |
| public static Vector2[] RandomPerlinPoint(System.Random generator) { | |
| float randomX1 = (float)generator.NextDouble(); | |
| float randomX2 = (float)generator.NextDouble(); | |
| float randomY1 = (float)generator.NextDouble(); | |
| float randomY2 = (float)generator.NextDouble(); | |
| return new Vector2[] { new Vector2(randomX1, randomY1), new Vector2(randomX2, randomY2) }; | |
| } | |
| public static Vector2 RandomPerlinNoisePos(System.Random generator) { | |
| Vector2[] points = RandomPerlinPoint(generator); | |
| Vector2 point = new Vector2( | |
| Mathf.PerlinNoise(points[0].x, points[0].y) + generator.Next((int)-worldSize / 2, (int)worldSize / 2), | |
| Mathf.PerlinNoise(points[1].x, points[1].y) + generator.Next((int)-worldSize / 2, (int)worldSize / 2) | |
| ); | |
| while (Collides(point)) { | |
| point = new Vector2( | |
| Mathf.PerlinNoise(points[0].x, points[0].y) + generator.Next((int)-worldSize / 2, (int)worldSize / 2), | |
| Mathf.PerlinNoise(points[1].x, points[1].y) + generator.Next((int)-worldSize / 2, (int)worldSize / 2) | |
| ); | |
| } | |
| return point; | |
| } | |
| public static Vector2 RandomPerlinNoisePos(Vector2 minBounds, Vector2 maxBounds, System.Random generator) { | |
| Vector2[] points = RandomPerlinPoint(generator); | |
| Vector2 point = new Vector2( | |
| Mathf.PerlinNoise(points[0].x, points[0].y) + generator.Next((int)minBounds.x, (int)maxBounds.x), | |
| Mathf.PerlinNoise(points[1].x, points[1].y) + generator.Next((int)minBounds.y, (int)maxBounds.y) | |
| ); | |
| while (Collides(point)) { | |
| point = new Vector2( | |
| Mathf.PerlinNoise(points[0].x, points[0].y) + generator.Next((int)minBounds.x, (int)maxBounds.x), | |
| Mathf.PerlinNoise(points[1].x, points[1].y) + generator.Next((int)minBounds.y, (int)maxBounds.y) | |
| ); | |
| } | |
| return point; | |
| } | |
| public static bool Collides(Vector2 point) { | |
| foreach (Collider2D collider in Object.FindObjectsOfType<Collider2D>()) { | |
| if (collider.gameObject.layer == LayerMask.NameToLayer("Obstacles") && collider.bounds.Contains(point)) return true; | |
| } | |
| return false; | |
| } | |
| Vector2[] GenBiomeArea(int minSize, int maxSize, System.Random generator) { | |
| float width = generator.Next(minSize, maxSize); | |
| float height = generator.Next(minSize, maxSize); | |
| Vector2 minBounds = new Vector2( | |
| generator.Next((int)-worldSize / 2, ((int)worldSize / 2) - (int)width), | |
| generator.Next((int)-worldSize / 2, ((int)worldSize / 2) - (int)height) | |
| ); | |
| Vector2 maxBounds = minBounds + new Vector2(width, height); | |
| return new Vector2[] { minBounds, maxBounds }; | |
| } | |
| Rect BiomeRect(Vector2[] bounds, float border) { | |
| return Rect.MinMaxRect(bounds[0].x - border, bounds[0].y - border, bounds[1].x + border, bounds[1].y + border); | |
| } | |
| void GenDirt() { | |
| GameController.instance.SetLoadingMessage("Generating dirt..."); | |
| for (int i = 0; i < maxDirt; i++) { | |
| Object.Instantiate(dirt, RandomPerlinNoisePos(masterRng), Quaternion.identity); | |
| } | |
| } | |
| void GenTallGrass() { | |
| GameController.instance.SetLoadingMessage("Generating tall grass..."); | |
| for (int i = 0; i < maxTallGrass; i++) { | |
| Object.Instantiate(tallGrass, RandomPerlinNoisePos(rng), Quaternion.identity); | |
| } | |
| } | |
| void GenTrees() { | |
| GameController.instance.SetLoadingMessage("Generating trees..."); | |
| for (int i = 0; i < maxForests; i++) { | |
| Vector2[] bounds = GenBiomeArea((int)worldSize / 16, (int)worldSize / 10, masterRng); | |
| for (int j = 0; j < maxTrees / maxForests; j++) { | |
| int randomTree = masterRng.Next(0, 2); | |
| Vector3 pos = masterRng.Next(0, 2) == 0 ? RandomPerlinNoisePos(masterRng) : RandomPerlinNoisePos(bounds[0], bounds[1], masterRng); | |
| if (swampBounds.Any(b => b.Contains(pos))) randomTree = 2; | |
| Object.Instantiate(trees[randomTree], pos, Quaternion.identity); | |
| } | |
| } | |
| } | |
| void GenFruitBushes() { | |
| GameController.instance.SetLoadingMessage("Generating fruit bushes..."); | |
| for (int i = 0; i < maxFruitBushes; i++) { | |
| Object.Instantiate(fruitBush, RandomPerlinNoisePos(masterRng), Quaternion.identity); | |
| } | |
| } | |
| void GenOreNodes() { | |
| GameController.instance.SetLoadingMessage("Generating ore nodes..."); | |
| for (int i = 0; i < maxRockBiomes; i++) { | |
| Vector2[] bounds = GenBiomeArea((int)worldSize / 30, (int)worldSize / 15, masterRng); | |
| string oreType = ""; | |
| switch (masterRng.Next(0, 4)) { | |
| case 0: | |
| oreType = "coppernode"; | |
| break; | |
| case 1: | |
| oreType = "tinnode"; | |
| break; | |
| case 2: | |
| oreType = "ironnode"; | |
| break; | |
| case 3: | |
| oreType = "coalnode"; | |
| break; | |
| } | |
| for (int j = 0; j < maxOreNodes / maxRockBiomes; j++) { | |
| GameObject node = Object.Instantiate(oreNode, RandomPerlinNoisePos(bounds[0], bounds[1], masterRng), Quaternion.identity); | |
| node.GetComponent<OreNode>().spriteName = oreType; | |
| node.GetComponent<OreNode>().SetSprite(); | |
| } | |
| } | |
| } | |
| void GenWorldItems() { | |
| GameController.instance.SetLoadingMessage("Spawning world items..."); | |
| for (int i = 0; i < maxBranches; i++) { | |
| PhotonNetwork.InstantiateSceneObject("WorldItems/Branch", RandomPerlinNoisePos(masterRng), Quaternion.identity); | |
| } | |
| for (int i = 0; i < maxRocks; i++) { | |
| PhotonNetwork.InstantiateSceneObject("WorldItems/Rock", RandomPerlinNoisePos(masterRng), Quaternion.identity); | |
| } | |
| } | |
| void GenAnimals() { | |
| GameController.instance.SetLoadingMessage("Spawning animals..."); | |
| for (int i = 0; i < maxAnimals; i++) { | |
| string randomAnimal = ""; | |
| switch (masterRng.Next(0, 3)) { | |
| case 0: | |
| randomAnimal = "Bear"; | |
| break; | |
| case 1: | |
| randomAnimal = "Chicken"; | |
| break; | |
| case 2: | |
| randomAnimal = "Rabbit"; | |
| break; | |
| } | |
| PhotonNetwork.InstantiateSceneObject("Animals/" + randomAnimal, RandomPerlinNoisePos(masterRng), Quaternion.identity); | |
| } | |
| } | |
| void GenDecals() { | |
| GameController.instance.SetLoadingMessage("Generating decals..."); | |
| for (int i = 0; i < maxDecals; i++) { | |
| Object.Instantiate(decal, RandomPerlinNoisePos(rng), Quaternion.identity); | |
| } | |
| } | |
| void GenSwamps() { | |
| GameController.instance.SetLoadingMessage("Generating swamps..."); | |
| swampBounds = new Rect[maxSwamps]; | |
| for(int i = 0; i < maxSwamps; i++) { | |
| Vector2[] bounds = GenBiomeArea((int)worldSize / 8, (int)worldSize / 3, rng); | |
| swampBounds[i] = BiomeRect(bounds, 2f); | |
| GenSwampWater(swampBounds[i]); | |
| for (int j = 0; j < maxSwampGrass / maxSwamps; j++) { | |
| Vector3 pos = RandomPerlinNoisePos(bounds[0], bounds[1], rng); | |
| Object.Instantiate(swampGrass, pos, Quaternion.identity); | |
| } | |
| } | |
| } | |
| void GenRivers() { | |
| GameController.instance.SetLoadingMessage("Generating rivers..."); | |
| AstarPath astarPath = GameObject.Find("A*").GetComponent<AstarPath>(); | |
| astarPath.Scan(astarPath.graphs[0]); | |
| List<GameObject> waterPoints = new List<GameObject>(); | |
| for (int i = 0; i < maxRivers; i++) { | |
| List<Vector2> points = new List<Vector2>(); | |
| int numPoints = masterRng.Next(3, 8); | |
| for (int j = 0; j < numPoints; j++) { | |
| if (j == 0 || j == numPoints - 1) { | |
| // First and last points are on the edge of the map | |
| switch (Random.Range(0, 4)) { | |
| case 0: | |
| // Top | |
| points.Add(new Vector2(RandomPerlinNoisePos(masterRng).x, worldSize)); | |
| break; | |
| case 1: | |
| // Left | |
| points.Add(new Vector2(-worldSize, RandomPerlinNoisePos(masterRng).y)); | |
| break; | |
| case 2: | |
| // Bottom | |
| points.Add(new Vector2(RandomPerlinNoisePos(masterRng).x, -worldSize)); | |
| break; | |
| case 3: | |
| // Right | |
| points.Add(new Vector2(worldSize, RandomPerlinNoisePos(masterRng).y)); | |
| break; | |
| } | |
| } else { | |
| points.Add(RandomPerlinNoisePos(masterRng)); | |
| } | |
| waterPoints.Add(Object.Instantiate(riverSeeker, points[j], Quaternion.identity)); | |
| } | |
| for (int j = 0; j < numPoints - 1; j++) { | |
| waterPoints[j].GetComponent<Seeker>().StartPath(points[j], points[j + 1], OnRiverPathComplete); | |
| } | |
| } | |
| } | |
| void OnRiverPathComplete(Path p) { | |
| foreach (Vector3 waypoint in p.vectorPath) { | |
| Object.Instantiate(water, waypoint, Quaternion.identity); | |
| } | |
| } | |
| void GenAmbientSounds() { | |
| if (PhotonNetwork.IsMasterClient) GameController.instance.SetLoadingMessage("Generating ambience..."); | |
| for (int i = 0; i < maxAmbientSounds; i++) { | |
| int randomAmbience = rng.Next(0, 2); | |
| Vector3 pos = RandomPerlinNoisePos(rng); | |
| Object.Instantiate(ambience[randomAmbience], pos, Quaternion.identity); | |
| } | |
| } | |
| void GenSwampWater(Rect bounds) { | |
| AstarPath astarPath = GameObject.Find("A*").GetComponent<AstarPath>(); | |
| astarPath.Scan(astarPath.graphs[0]); | |
| List<GameObject> waterPoints = new List<GameObject>(); | |
| for (int i = 0; i < maxSwampRivers; i++) { | |
| List<Vector2> points = new List<Vector2>(); | |
| int numPoints = masterRng.Next(8, 16); | |
| for (int j = 0; j < numPoints; j++) { | |
| if(j == numPoints - 1) { | |
| points.Add(points[0]); | |
| } else { | |
| points.Add(new Vector2(rng.Next((int)bounds.x, (int)(bounds.x + bounds.width)), rng.Next((int)bounds.y, (int)(bounds.y + bounds.height)))); | |
| } | |
| waterPoints.Add(Object.Instantiate(riverSeeker, points[j], Quaternion.identity)); | |
| } | |
| for (int j = 0; j < numPoints - 1; j++) { | |
| waterPoints[j].GetComponent<Seeker>().StartPath(points[j], points[j + 1], OnSwampRiverPathComplete); | |
| } | |
| } | |
| } | |
| void OnSwampRiverPathComplete(Path p) { | |
| foreach (Vector3 waypoint in p.vectorPath) { | |
| GameObject swampWater = Object.Instantiate(water, waypoint, Quaternion.identity); | |
| swampWater.GetComponent<SpriteRenderer>().color = new Color(0.5f, 0.8f, 0.5f); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment