Advertisement
matbiz01

terrain generator

Jan 21st, 2021
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.43 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5.  
  6. public class TerrainGenerator : MonoBehaviour //############ i believe that this code works only for chunks with even size !!!!!!!!!!!!!!
  7. {
  8.     public const int MaxDev = 20; // maximum deviation for the new seed
  9.     public int[] localSeed = new[] { -1, -1, -1, -1 }; //density%, grass%, bush%, tree%
  10.     private int[] initSeed = new[] { 40, 50, 20, 30 };
  11.     public List<string> elementNames; //elementNames[1] corresponds to localSeed[1]
  12.     private Dictionary<string, bool> takenArea = new Dictionary<string, bool>();
  13.  
  14.     private struct TerrainElement
  15.     {
  16.         public GameObject prefab;
  17.         public int width;
  18.         public int height;
  19.         public int area;
  20.         public int layer;
  21.         public TerrainElement(GameObject prefab, int width, int height, int layer)
  22.         {
  23.             this.prefab = prefab;
  24.             this.width = width;
  25.             this.height = height;
  26.             this.layer = layer;
  27.             this.area = height * width;
  28.         }
  29.     }
  30.     Dictionary<string, TerrainElement> terrainElements;
  31.  
  32.     private void Awake()
  33.     {
  34.         elementNames = new List<string>();
  35.         elementNames.Add("empty");
  36.         terrainElements = new Dictionary<string, TerrainElement>();
  37.         TerrainElement tree = new TerrainElement(Resources.Load<GameObject>("Prefabs/Tree"), 3, 3, -4); //width, height, layer
  38.         TerrainElement bush = new TerrainElement(Resources.Load<GameObject>("Prefabs/Bush"), 1, 1, -2);
  39.         TerrainElement grass = new TerrainElement(Resources.Load<GameObject>("Prefabs/Grass"), 1, 1, -1);
  40.  
  41.         elementNames.Add("grass");
  42.         terrainElements.Add("grass", grass);  //seed[1]
  43.         elementNames.Add("bush");
  44.         terrainElements.Add("bush", bush); // seed[2]
  45.         elementNames.Add("tree");
  46.         terrainElements.Add("tree", tree); // seed[3]
  47.     }
  48.  
  49.     public void Initialize(List<int[]> seeds)
  50.     {
  51.         localSeed = GenerateSeed(seeds);
  52.         GenerateTerrain(localSeed);
  53.     }
  54.  
  55.     public void GenerateTerrain(int[] seed)
  56.     {
  57.         /*
  58.          * chunk size - 121
  59.          * bush size - 1 data - 1
  60.          * grass size - 1 data - 2
  61.          * tree size - 4 data - 3
  62.         */
  63.         if (IsSeedProper(seed))
  64.         {
  65.             int freeArea = Chunk.ChunkSize * Chunk.ChunkSize * seed[0] / 100;
  66.             int amount;
  67.             for (int x = 1; x < elementNames.Count; x++)
  68.             {
  69.                 TerrainElement toLoad = terrainElements[elementNames[x]];
  70.                 amount = freeArea * seed[x] / 100 / toLoad.area;
  71.                 SpawnStruct(toLoad, amount);
  72.             }
  73.         }
  74.  
  75.     }
  76.  
  77.     private void SpawnStruct(TerrainElement terrainElement, int amount)
  78.     {
  79.         GameObject prefab = terrainElement.prefab;
  80.         int width = terrainElement.width;
  81.         int height = terrainElement.height;
  82.         int fromCenter = Mathf.RoundToInt(Chunk.fromCenter);
  83.         Vector3 spot;
  84.         int x = Random.Range(-fromCenter, fromCenter - width + 1); //makes sure that whole terrain element gets spawned inside of the chunk
  85.         int y = Random.Range(-fromCenter + height, fromCenter + 1); //because x and y represent top left 1x1 part of the element
  86.         for (int i = 0; i < amount; i++)
  87.         {
  88.             while (!DoesFit(x, y, width, height)) //checks if terrain element can fit if it's top right corner is at x y
  89.             {
  90.                 x = Random.Range(-fromCenter, fromCenter - width + 1);
  91.                 y = Random.Range(-fromCenter + height, fromCenter + 1);
  92.             }
  93.  
  94.             spot = new Vector3(x + width / 2f, y - height / 2f, 0); //we align the sprite with the grid
  95.             GameObject temp;
  96.             temp = Instantiate(prefab, transform.position + spot, Quaternion.identity);
  97.             temp.transform.parent = gameObject.transform;
  98.             temp.transform.position += new Vector3(0, 0, terrainElement.layer);
  99.         }
  100.     }
  101.  
  102.     private string VecToString(int x, int y)
  103.     {
  104.         return x.ToString() + y.ToString();
  105.     }
  106.  
  107.     private bool DoesFit(int xPos, int yPos, int width, int height){
  108.         for(int x = xPos; x < xPos + width; x++) //xpos and ypos represent top left of element, so we need to check the rest of the right side for obstructions
  109.         {
  110.             for(int y = yPos; y > yPos - height; y--) // same, as above, but this time we check the area below y
  111.             {
  112.                 if (takenArea.ContainsKey(VecToString(x, y)))
  113.                 {
  114.                     return false;
  115.                 }
  116.             }
  117.         }
  118.         for (int x = xPos; x < xPos + width; x++) //only works if we can safely insert element onto the chunk, fills out taken area
  119.         {
  120.             for (int y = yPos; y > yPos - height; y--)
  121.             {
  122.                 takenArea.Add(VecToString(x, y), true);
  123.             }
  124.         }
  125.         return true;
  126.     }
  127.  
  128.     public int[] GenerateSeed(List<int[]> seeds)
  129.     {
  130.         int paramCount = Chunk.Params;
  131.  
  132.         List<int[]> initializedSeeds = new List<int[]>();
  133.         foreach(int[] seed in seeds) // we filter out empty seeds and store them in nonNullSeeds
  134.         {
  135.             if(IsSeedProper(seed))
  136.             {
  137.                 initializedSeeds.Add(seed);
  138.             }
  139.         }
  140.         if(initializedSeeds.Count == 0) // if every single seed was null we give our seed a random value
  141.         {
  142.             return new int[] {35, 50, 25, 25};
  143.         }
  144.        
  145.         int[] averageOfParams = new int[paramCount]; //this array will be used to get the average of parameters from neighbouring cells
  146.         System.Array.Clear(averageOfParams, 0, paramCount); // fill out with zeros
  147.  
  148.         foreach (int[] seed in initializedSeeds) //we sum up seed values
  149.         {
  150.             for(int x = 0; x < paramCount; x++)
  151.             {
  152.                 averageOfParams[x] += seed[x];
  153.             }
  154.         }
  155.  
  156.         for(int x = 0; x < paramCount; x++) //gets the average for every value and randomly changes it by Max Deviation value
  157.         {
  158.             averageOfParams[x] /= initializedSeeds.Count;
  159.             if(x != 0)
  160.             {
  161.                 averageOfParams[x] += Random.Range(-MaxDev, MaxDev);
  162.                 if(averageOfParams[x] < 10)
  163.                 {
  164.                     averageOfParams[x] = 10;
  165.                 }
  166.                 if(averageOfParams[x] >= 100)
  167.                 {
  168.                     averageOfParams[x] = 99;
  169.                 }
  170.             }
  171.         }
  172.  
  173.         int leftTo100 = 100 - ArraySum(averageOfParams, 1, averageOfParams.Length - 1); // checks how far off are we from 100%
  174.  
  175.         int changeBy = leftTo100 / 3;
  176.         int lastAdj = leftTo100 - changeBy * 3;
  177.         for(int x = 1; x < paramCount; x++)
  178.         {
  179.             averageOfParams[x] += changeBy;
  180.         }
  181.         averageOfParams[Random.Range(1, 4)] += lastAdj;
  182.  
  183.         return averageOfParams;
  184.     }
  185.  
  186.     private int ArraySum(int[] arr, int start, int end)
  187.     {
  188.         int total = 0;
  189.         for(int x = start; x <= end; x++)
  190.         {
  191.             total += arr[x];
  192.         }
  193.         return total;
  194.     }
  195.  
  196.     public int[] GetSeed()
  197.     {
  198.         return localSeed;
  199.     }
  200.  
  201.     public bool IsSeedProper(int[] seed)
  202.     {
  203.        
  204.         foreach(int x in seed)
  205.         {
  206.             if(x < 0)
  207.             {
  208.                 return false;
  209.             }
  210.         }
  211.         return true;
  212.     }
  213. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement