azrith001

WorldGenerator.cs

Aug 14th, 2020
244
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System;
  5. using Unity.Mathematics;
  6. using UnityEditor;
  7.  
  8. public class WorldGenerator : MonoBehaviour
  9. {
  10.  
  11.     // Base World Data
  12.     public int ChunkSize = 75;
  13.     public string Seed = "";
  14.     [Range(1f, 300f)]
  15.     public float PerlinScale = 100f;
  16.     [Range(1, 100)]
  17.     public int PerlinOctaves = 5;
  18.     public float persistence = 2f;
  19.     public float lacunarity = 2f;
  20.     [Range(0.001f, 3.000f)]
  21.     public float PerlinBaseAmplitude = 1f;
  22.     // Random World Offset
  23.     private float xOffset;
  24.     private float yOffset;
  25.     // Pseudo Random Number Generator
  26.     private System.Random pseudoRandom;
  27.  
  28.     // Chunk Data Split into Sections (Each Chunk having Coords (x, y))
  29.     public Dictionary<string, WorldChunk> chunks = new Dictionary<string, WorldChunk>();
  30.     public List<WorldChunk> ActiveChunks = new List<WorldChunk>();
  31.  
  32.     // Get previous load position in world
  33.     private Vector2Int prevChunkPos = new Vector2Int(0,0);
  34.  
  35.  
  36.     //============================================================
  37.     // Set Warm-Up Data
  38.     //============================================================
  39.     private void Awake() {
  40.         // Get/Create Seed
  41.         if (Seed == ""){
  42.             Seed = GenerateRandomSeed();
  43.         }
  44.         // Get Random Number Generator
  45.         pseudoRandom = new System.Random(Seed.GetHashCode());
  46.          // Set Offsets from seed (new world each time)
  47.         xOffset = pseudoRandom.Next(-10000, 10000);
  48.         yOffset = pseudoRandom.Next(-10000, 10000);
  49.  
  50.         // Using to Clear while Making Test Adjustments
  51.         chunks.Clear();
  52.         ActiveChunks.Clear();
  53.         // Generate Starting Chunk
  54.         for (int x = -1; x <= 1; x++)
  55.         {
  56.             for (int y = -1; y <= 1; y++)
  57.             {
  58.                 // Draw Test Chunks
  59.                 GenerateChunk(x, y);
  60.                 WorldChunk c = GetChunk(x,y);
  61.                 // Enable the Chunk and Add it To The Active List
  62.                 c.enabled = true;
  63.                 ActiveChunks.Add(c);
  64.             }
  65.         }
  66.     }
  67.  
  68.     private void Update() {
  69.         int2 chunkPos = new int2(0, 0);
  70.         // Get X/Y Offsets for camera to correctly load new chunks (this will be updated to work with camera bounds later instead this is just temporary)
  71.         if (Camera.main.transform.position.x >= 0){
  72.             chunkPos.x = (int)((Camera.main.transform.position.x+ChunkSize/2) / ChunkSize);
  73.         } else {
  74.             chunkPos.x = (int)((Camera.main.transform.position.x-ChunkSize/2) / ChunkSize);
  75.         }
  76.  
  77.         if (Camera.main.transform.position.y >= 0){
  78.             chunkPos.y = (int)((Camera.main.transform.position.y+ChunkSize/2) / ChunkSize);
  79.         } else {
  80.             chunkPos.y = (int)((Camera.main.transform.position.y-ChunkSize/2) / ChunkSize);
  81.         }
  82.  
  83.         // Generate new Chunks if they don't exist & Enable Active Chunks
  84.         EnableChunks(chunkPos);
  85.     }
  86.  
  87.     // ===
  88.     //  Enable Chunk at position and surrounding chunks, disable all active chunks outsize area
  89.     // ===
  90.     private void EnableChunks(int2 chunkPosition){
  91.         // Check if needs to update
  92.         Vector2Int cpos = new Vector2Int(chunkPosition.x, chunkPosition.y);
  93.         if (!PositionIsNew(cpos)){
  94.             return;
  95.         }
  96.         // Get offsets
  97.         List<int2> offsets = new List<int2>();
  98.         // Add 1, 1 & -1, -1  and so on for full square
  99.         offsets.Add(new int2(0, 1));
  100.         offsets.Add(new int2(0, -1));
  101.         offsets.Add(new int2(1, 0));
  102.         offsets.Add(new int2(-1, 0));
  103.         offsets.Add(new int2(0, 0));
  104.         // Set all Active Chunks Inactive
  105.         foreach (int2 offset in offsets)
  106.         {
  107.             for (int i = 0; i < ActiveChunks.Count; i++)
  108.             {
  109.                 // Check if the Chunk exists in active List (this is to reduce lag when loading and unloading chunks)
  110.                 // So you don't cycle through all the chunks to see what is enabled
  111.                 if (ActiveChunks[i] != null){
  112.                     // If it does disable it and remove it from the list
  113.                     ActiveChunks[i].enabled = false;
  114.                     ActiveChunks.RemoveAt(i);
  115.                 }
  116.             }
  117.         }
  118.         // Cycle offsets and Enable All Chunks within
  119.         foreach (int2 offset in offsets)
  120.         {
  121.             WorldChunk offsetChunk = GetChunk(chunkPosition.x + offset.x, chunkPosition.y + offset.y);
  122.             offsetChunk.enabled = true;
  123.             ActiveChunks.Add(offsetChunk);
  124.         }
  125.         prevChunkPos = cpos;
  126.     }
  127.  
  128.     // ===
  129.     //  BOOL - Check if current pos is the same as old
  130.     // ===
  131.     public bool PositionIsNew(Vector2Int position){
  132.         return (prevChunkPos != position);
  133.     }
  134.  
  135.     //============================================================
  136.     // Generation Code
  137.     //============================================================
  138.  
  139.     // ===
  140.     //  Create New Chunks
  141.     // ===
  142.     public void GenerateChunk(int x, int y){
  143.         // Set Key to use
  144.         string key = $"{x},{y}";
  145.         // Check if key exists if not Generate New Chunk
  146.         if (!chunks.ContainsKey(key)){
  147.             // Add Chunk, Set Position in chunk grid (for calling and block data later), Then Generate data
  148.             chunks.Add(key, new WorldChunk(ChunkSize));
  149.             chunks[key].Position = new int2(x, y);
  150.             GenerateChunkData(chunks[key]);
  151.         }
  152.     }
  153.     // ===
  154.     //  Get Current Chunk From X/Y or INt2
  155.     // ===
  156.     public WorldChunk GetChunk(int x, int y){
  157.         // Set Key to use
  158.         string key = $"{x},{y}";
  159.         // Check if key exists if not Generate New Chunk
  160.         if (chunks.ContainsKey(key)){
  161.             return chunks[key];
  162.         } else {
  163.             GenerateChunk(x,y);
  164.             return chunks[key];
  165.         }
  166.     }
  167.  
  168.     public WorldChunk GetChunk(int2 intpos){
  169.         return GetChunk(intpos.x, intpos.y);
  170.     }
  171.     // ===
  172.     //  Fill Chunks with Perlin Data
  173.     // ===
  174.     private void GenerateChunkData(WorldChunk chunk){
  175.         // Set min / max
  176.         float maxNoiseHeight = float.MaxValue;
  177.         float minNoiseHeight = float.MinValue;
  178.        // Set Max Height for World
  179.         float maxPossibleHeight = 0;
  180.         float amplitude = PerlinBaseAmplitude;
  181.         for (int i = 0; i < PerlinOctaves; i++)
  182.         {
  183.             maxPossibleHeight += amplitude;
  184.             amplitude *= persistence;
  185.         }
  186.         // Set Data to Chunk
  187.         for (int x = 0; x <= ChunkSize; x++)
  188.         {
  189.             for (int y = 0; y <= ChunkSize; y++)
  190.             {
  191.                 int2 cellPos = chunk.CellPosition(x, y);
  192.  
  193.                 amplitude = PerlinBaseAmplitude;
  194.                 float freq = 1;
  195.                 float noiseHeight = 0;
  196.                 // Get Perlin Map
  197.                 for (int i = 0; i < PerlinOctaves; i++)
  198.                 {
  199.                     float px = (float)(cellPos.x + xOffset) / PerlinScale * freq + xOffset;
  200.                     float py = (float)(cellPos.y + yOffset) / PerlinScale * freq + yOffset;
  201.  
  202.                     // Set Temp Sample For Testing (This will change for Map Data (Hills and Water) later)
  203.                     float PerlinValue = Mathf.PerlinNoise(px, py) * 2 - 1;
  204.                     noiseHeight += PerlinValue * amplitude;
  205.  
  206.                     // Increase amp and freq
  207.                     amplitude *= persistence;
  208.                     freq *= lacunarity;
  209.                 }
  210.  
  211.                 // Adjust Min and Max
  212.                 if (noiseHeight > maxNoiseHeight){
  213.                     maxNoiseHeight = noiseHeight;
  214.                 } else if (noiseHeight < minNoiseHeight){
  215.                     minNoiseHeight = noiseHeight;
  216.                 }
  217.                
  218.                 // Set Sample for Chunk
  219.                 chunk.Sample[x,y] = noiseHeight;
  220.             }
  221.         }
  222.  
  223.         // Normalize Sample to fit world Sample Height
  224.         for (int x = 0; x <= ChunkSize; x++)
  225.         {
  226.             for (int y = 0; y <= ChunkSize; y++)
  227.             {
  228.                 float normalizedHeight = (chunk.Sample[x,y] + 1) / (2f * maxPossibleHeight / 1.75f);
  229.                 chunk.Sample[x,y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue);
  230.             }
  231.         }
  232.     }
  233.  
  234.     // ===
  235.     //  Generate Random Seed of Length
  236.     // ===
  237.     private string GenerateRandomSeed(int maxCharAmount = 10, int minCharAmount = 10){
  238.         //Set Characters To Pick from
  239.         const string glyphs= "abcdefghijklmnopqrstuvwxyz0123456789";
  240.         //Set Length from min to max
  241.         int charAmount = UnityEngine.Random.Range(minCharAmount, maxCharAmount);
  242.         // Set output Variable
  243.         string output = "";
  244.         // Do Random Addition
  245.         for(int i=0; i<charAmount; i++)
  246.         {
  247.             output += glyphs[UnityEngine.Random.Range(0, glyphs.Length)];
  248.         }
  249.         // Output New Random String
  250.         return output;
  251.     }
  252.  
  253.     //============================================================
  254.     // Draw Example
  255.     //============================================================
  256.     private void OnDrawGizmos() {
  257.         if (!EditorApplication.isPlaying){
  258.         // For Live Editing Values before playing (Must enable Gizmos)
  259.         Awake();
  260.         }
  261.         // For Each WorldChunk in the chunk Data
  262.         foreach (WorldChunk c in chunks.Values)
  263.         {
  264.             // Check if it exists (Foreach is stupid sometimes... When live editing)
  265.             if (c != null){
  266.                 if (c.enabled == true){
  267.                 // Get World Positions for Chunk (Should probably Set to a Variable in the Chunk Data)
  268.                 Vector3 ChunkPosition = new Vector3(c.Position.x * ChunkSize, c.Position.y * ChunkSize);
  269.                 // For Each X & For Each Y in the chunk
  270.                 for (int x = 0; x <= ChunkSize; x++)
  271.                     {
  272.                         for (int y = 0; y <= ChunkSize; y++)
  273.                         {
  274.                            
  275.                             // Get Cell position
  276.                             Vector3 cellPos = c.VectorCellPosition(x,y);
  277.                             // Get Temp Sample and set to color
  278.                             float samp = c.Sample[x,y];
  279.                             if (cellPos.x == 0 && cellPos.y == 0 && c.Position.x == 0 && c.Position.y == 0){
  280.                                 Gizmos.color = new Color(0f, 1f, 0f);
  281.                             }else {
  282.                                 Gizmos.color = new Color(samp, samp, samp);
  283.                             }
  284.                             // Draw Tile as Sample black or white.
  285.                             Gizmos.DrawCube(cellPos, Vector3.one);
  286.                         }
  287.                     }
  288.                 }
  289.                
  290.             }
  291.         }
  292.        
  293.     }
  294. }
  295.  
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×