Advertisement
JontePonte

Very good voxel engine

Jul 27th, 2024
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 21.99 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using Unity.Collections;
  3. using UnityEngine;
  4. using Unity.Mathematics;
  5. using Unity.Jobs;
  6. using UnityEngine.Rendering;
  7.  
  8. public class ChunkGenerator : MonoBehaviour
  9. {
  10.     public Texture2D atlas;
  11.     public int maxVoxelHeight;
  12.     public Vector3Int chunkDimensions;
  13.  
  14.     public int maxProccessingFrames;
  15.    
  16.     public static int MaxVoxelHeight;
  17.  
  18.     [Header("Noise Settings")]
  19.     public float persistance;
  20.     public float frequency;
  21.     public float lacunarity;
  22.     public int numOfOctaves;
  23.     public Vector2Int offset;
  24.     public float heightMultiplier;
  25.  
  26.     [Header(" ")]
  27.     public string executionTime;
  28.  
  29.     Noise noise;
  30.  
  31.     NativeArray<int3> faceVertices;
  32.     NativeArray<int3> faceDirections;
  33.     NativeArray<float2> uvCoordinates;
  34.  
  35.     [HideInInspector]
  36.     public NativeHashMap<int2, NativeArray<int>> chunkDataMap;
  37.  
  38.     List<JobData> jobList;
  39.  
  40.     private void Start()
  41.     {
  42.         Initialize();
  43.         executionTime = "N/A";
  44.     }
  45.  
  46.     public void GenerateChunk()
  47.     {
  48.         Initialize();
  49.  
  50.         if(GameObject.Find("Chunk") == null)
  51.         {
  52.             float startTime = Time.realtimeSinceStartup;
  53.  
  54.             CreateChunkObject(offset);
  55.             CompleteJobs(false);
  56.  
  57.             executionTime = (Time.realtimeSinceStartup - startTime) * 1000f + " ms";
  58.         }
  59.  
  60.         else
  61.         {
  62.             float startTime = Time.realtimeSinceStartup;
  63.  
  64.             Mesh mesh = CreateChunkMesh(offset);
  65.             CompleteJobs(false);
  66.  
  67.             executionTime = (Time.realtimeSinceStartup - startTime) * 1000f + " ms";
  68.  
  69.             GameObject.Find("Chunk").GetComponent<MeshFilter>().mesh = mesh;
  70.         }
  71.        
  72.        
  73.  
  74.         faceVertices.Dispose();
  75.         faceDirections.Dispose();
  76.         uvCoordinates.Dispose();
  77.     }
  78.  
  79.     public GameObject CreateChunkObject(Vector2Int offset)
  80.     {
  81.         GameObject chunk = new GameObject("Chunk");
  82.         var meshRenderer = chunk.AddComponent<MeshRenderer>();
  83.         meshRenderer.sharedMaterial = new Material(Shader.Find("Unlit/Texture"))
  84.         {
  85.             mainTexture = atlas
  86.         };
  87.  
  88.         chunk.AddComponent<MeshFilter>().mesh = CreateChunkMesh(offset);
  89.  
  90.         return chunk;
  91.     }
  92.  
  93.     public Mesh CreateChunkMesh(Vector2Int offset, NativeArray<int> customVoxelValues = default)
  94.     {
  95.         Mesh mesh = new Mesh
  96.         {
  97.             indexFormat = IndexFormat.UInt32
  98.         };
  99.  
  100.         NativeList<float3> vertices = new NativeList<float3>(Allocator.TempJob);
  101.         NativeList<int> triangles = new NativeList<int>(Allocator.TempJob);
  102.         NativeList<float2> uvs = new NativeList<float2>(Allocator.TempJob);
  103.  
  104.         int2 intOffset = new int2(offset.x, offset.y);
  105.  
  106.         if(customVoxelValues == default){
  107.  
  108.             if (!chunkDataMap.ContainsKey(intOffset))
  109.                 chunkDataMap.Add(intOffset, noise.GenerateVoxelValues(offset));
  110.         }
  111.         else{
  112.  
  113.             if (!chunkDataMap.ContainsKey(intOffset))
  114.                 chunkDataMap.Add(intOffset, customVoxelValues);
  115.         }
  116.        
  117.  
  118.         AddNeighboringChunkData(intOffset, offset);
  119.  
  120.  
  121.         ChunkJob job = new ChunkJob
  122.         {
  123.             vertices = vertices,
  124.             triangles = triangles,
  125.             uvs = uvs,
  126.  
  127.             thisChunkData = chunkDataMap[intOffset],
  128.             rightChunkData = chunkDataMap[intOffset + new int2(chunkDimensions.x, 0)],
  129.             leftChunkData = chunkDataMap[intOffset + new int2(-chunkDimensions.x, 0)],
  130.             frontChunkData = chunkDataMap[intOffset + new int2(0, chunkDimensions.z)],
  131.             backChunkData = chunkDataMap[intOffset + new int2(0, -chunkDimensions.z)],
  132.  
  133.             faceDirections = faceDirections,
  134.             uvCordinates = uvCoordinates,
  135.             faceVertices = faceVertices,
  136.             maxVoxelHeight = maxVoxelHeight
  137.         };
  138.  
  139.         JobHandle handle = job.Schedule();
  140.  
  141.         jobList.Add(new JobData
  142.         {
  143.             mesh = mesh,
  144.             handle = handle,
  145.             vertices = vertices,
  146.             triangles = triangles,
  147.             uvs = uvs,
  148.         });
  149.  
  150.         return mesh;
  151.     }
  152.  
  153.     private void AddNeighboringChunkData(int2 intOffset, Vector2Int offset)
  154.     {
  155.         if(!chunkDataMap.ContainsKey(intOffset + new int2(chunkDimensions.x, 0)))
  156.             chunkDataMap.Add(intOffset + new int2(chunkDimensions.x, 0), noise.GenerateVoxelValues(offset + Vector2Int.right * chunkDimensions.x));
  157.  
  158.         if (!chunkDataMap.ContainsKey(intOffset + new int2(-chunkDimensions.x, 0)))
  159.             chunkDataMap.Add(intOffset + new int2(-chunkDimensions.x, 0), noise.GenerateVoxelValues(offset + Vector2Int.left * chunkDimensions.x));
  160.  
  161.         if (!chunkDataMap.ContainsKey(intOffset + new int2(0, chunkDimensions.z)))
  162.             chunkDataMap.Add(intOffset + new int2(0, chunkDimensions.z), noise.GenerateVoxelValues(offset + Vector2Int.up * chunkDimensions.z));
  163.  
  164.         if (!chunkDataMap.ContainsKey(intOffset + new int2(0, -chunkDimensions.z)))
  165.             chunkDataMap.Add(intOffset + new int2(0, -chunkDimensions.z), noise.GenerateVoxelValues(offset + Vector2Int.down * 16));
  166.     }
  167.  
  168.  
  169.     public static int CalculateVoxelIndex(int x, int y, int z)
  170.     {
  171.         return x * (MaxVoxelHeight * 16) + y * 16 + z;
  172.     }
  173.  
  174.     private void LateUpdate()
  175.     {
  176.         CompleteJobs(true);
  177.     }
  178.  
  179.     void CompleteJobs(bool waitForCompletion)
  180.     {
  181.         for (int i = jobList.Count - 1; i >= 0; i--)
  182.         {
  183.             if (jobList[i].handle.IsCompleted || jobList[i].frameCount == maxProccessingFrames || !waitForCompletion)
  184.             {
  185.                 jobList[i].handle.Complete();
  186.  
  187.                 NativeArray<Vector3> vertexArray = jobList[i].vertices.AsArray().Reinterpret<Vector3>();
  188.                 NativeArray<int> triangleArray = jobList[i].triangles.AsArray();
  189.                 NativeArray<Vector2> uvArray = jobList[i].uvs.AsArray().Reinterpret<Vector2>();
  190.  
  191.                 // Assign data to mesh
  192.                 jobList[i].mesh.SetVertexBufferParams(vertexArray.Length, new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3));
  193.                 jobList[i].mesh.SetVertexBufferData(vertexArray, 0, 0, vertexArray.Length, 0, MeshUpdateFlags.Default);
  194.                 jobList[i].mesh.SetIndexBufferParams(triangleArray.Length, IndexFormat.UInt32);
  195.                 jobList[i].mesh.SetIndexBufferData(triangleArray, 0, 0, triangleArray.Length, MeshUpdateFlags.Default);
  196.                 jobList[i].mesh.SetSubMesh(0, new SubMeshDescriptor(0, triangleArray.Length), MeshUpdateFlags.Default);
  197.                 jobList[i].mesh.SetUVs(0, uvArray);
  198.  
  199.                 jobList[i].mesh.RecalculateBounds();
  200.  
  201.                 jobList[i].vertices.Dispose();
  202.                 jobList[i].triangles.Dispose();
  203.                 jobList[i].uvs.Dispose();
  204.             }
  205.  
  206.             jobList[i].frameCount++;
  207.             jobList.RemoveAt(i);
  208.         }
  209.  
  210.     }
  211.  
  212.  
  213.     class JobData
  214.     {
  215.         public JobHandle handle;
  216.  
  217.         public Mesh mesh;
  218.  
  219.         public NativeList<float3> vertices;
  220.         public NativeList<int> triangles;
  221.         public NativeList<float2> uvs;
  222.  
  223.         public int frameCount;
  224.     }
  225.  
  226.     private void Initialize()
  227.     {
  228.         chunkDataMap = new NativeHashMap<int2, NativeArray<int>>(1024, Allocator.Persistent);
  229.         jobList = new();
  230.         noise = new Noise(frequency, persistance, lacunarity, numOfOctaves, heightMultiplier, maxVoxelHeight);
  231.         MaxVoxelHeight = maxVoxelHeight;
  232.  
  233.         faceVertices = new NativeArray<int3>(24, Allocator.Persistent);
  234.  
  235.         //Bottom face
  236.         faceVertices[0] = new int3(1, 0, 0);
  237.         faceVertices[1] = new int3(1, 0, 1);
  238.         faceVertices[2] = new int3(0, 0, 1);
  239.         faceVertices[3] = new int3(0, 0, 0);
  240.  
  241.         //Front face
  242.         faceVertices[4] = new int3(1, 0, 1);
  243.         faceVertices[5] = new int3(1, 1, 1);
  244.         faceVertices[6] = new int3(0, 1, 1);
  245.         faceVertices[7] = new int3(0, 0, 1);
  246.  
  247.         //Back face
  248.         faceVertices[8] = new int3(0, 0, 0);
  249.         faceVertices[9] = new int3(0, 1, 0);
  250.         faceVertices[10] = new int3(1, 1, 0);
  251.         faceVertices[11] = new int3(1, 0, 0);
  252.  
  253.         //Left face
  254.         faceVertices[12] = new int3(0, 0, 1);
  255.         faceVertices[13] = new int3(0, 1, 1);
  256.         faceVertices[14] = new int3(0, 1, 0);
  257.         faceVertices[15] = new int3(0, 0, 0);
  258.  
  259.         //Right face
  260.         faceVertices[16] = new int3(1, 0, 0);
  261.         faceVertices[17] = new int3(1, 1, 0);
  262.         faceVertices[18] = new int3(1, 1, 1);
  263.         faceVertices[19] = new int3(1, 0, 1);
  264.  
  265.         //Top face
  266.         faceVertices[20] = new int3(0, 1, 0);
  267.         faceVertices[21] = new int3(0, 1, 1);
  268.         faceVertices[22] = new int3(1, 1, 1);
  269.         faceVertices[23] = new int3(1, 1, 0);
  270.  
  271.  
  272.         uvCoordinates = new NativeArray<float2>(6, Allocator.Persistent);
  273.  
  274.         uvCoordinates[0] = new float2(.5f, 0);
  275.         uvCoordinates[1] = new float2(.5f, .5f);
  276.         uvCoordinates[2] = new float2(.5f, .5f);
  277.         uvCoordinates[3] = new float2(.5f, .5f);
  278.         uvCoordinates[4] = new float2(.5f, .5f);
  279.         uvCoordinates[5] = new float2(0, 0);
  280.  
  281.  
  282.         faceDirections = new NativeArray<int3>(6, Allocator.Persistent);
  283.  
  284.         faceDirections[0] = new int3(0, -1, 0); // Down
  285.         faceDirections[1] = new int3(0, 0, 1);  // Forward
  286.         faceDirections[2] = new int3(0, 0, -1); // Back
  287.         faceDirections[3] = new int3(-1, 0, 0); // Left
  288.         faceDirections[4] = new int3(1, 0, 0);  // Right
  289.         faceDirections[5] = new int3(0, 1, 0);  // Up
  290.     }
  291.  
  292.  
  293.  
  294.     private void OnDestroy()
  295.     {
  296.         faceVertices.Dispose();
  297.         faceDirections.Dispose();
  298.         uvCoordinates.Dispose();
  299.  
  300.         foreach (var chunk in chunkDataMap)
  301.         {
  302.             chunk.Value.Dispose();
  303.         }
  304.  
  305.         chunkDataMap.Dispose();
  306.     }
  307. }
  308. using Unity.Collections;
  309. using UnityEngine;
  310.  
  311. public class Noise
  312. {
  313.     float frequency;
  314.     float lacunarity;
  315.     float persistance;
  316.     int numOfOctaves;
  317.  
  318.     float height;
  319.     public Noise(float frequency, float persistance, float lacunarity, int numOfOctaves, float height, int maxVoxelHeight)
  320.     {
  321.         this.frequency = frequency;
  322.         this.persistance = persistance;
  323.         this.lacunarity = lacunarity;
  324.         this.numOfOctaves = numOfOctaves;
  325.         this.height = height;
  326.     }
  327.  
  328.     public NativeArray<int> GenerateVoxelValues(Vector2Int offset)
  329.     {
  330.         int maxVoxelHeight = ChunkGenerator.MaxVoxelHeight;
  331.  
  332.         NativeArray<int> voxelValues = new NativeArray<int>(256 * maxVoxelHeight, Allocator.Persistent);
  333.  
  334.         for (int z = 0; z < 16; z++)
  335.         {
  336.             for (int x = 0; x < 16; x++)
  337.             {
  338.                 float noiseValue = CalculateNoiseValue(x, 0, z, offset);
  339.                 noiseValue *= height;
  340.                 noiseValue += maxVoxelHeight / 3;
  341.  
  342.                 for (int y = 0; y < maxVoxelHeight; y++)
  343.                 {
  344.                     if (y < noiseValue)
  345.                     {
  346.                         voxelValues[ChunkGenerator.CalculateVoxelIndex(x, y, z)] = 1;
  347.                     }
  348.                 }
  349.             }
  350.         }
  351.  
  352.         return voxelValues;
  353.  
  354.     }
  355.  
  356.     float CalculateNoiseValue(int x, int y, int z, Vector2Int offset)
  357.     {
  358.         float sum = 0;
  359.  
  360.         for (int i = 0; i < numOfOctaves; i++)
  361.         {
  362.             float frequency = Mathf.Pow(lacunarity, i) * this.frequency;
  363.             float amplitude = Mathf.Pow(persistance, i);
  364.  
  365.             sum += Mathf.PerlinNoise((x + offset.x) * frequency, (z + offset.y) * frequency) * amplitude;
  366.         }
  367.  
  368.         return sum / numOfOctaves;
  369.     }
  370. }
  371. using Unity.Burst;
  372. using Unity.Collections;
  373. using Unity.Jobs;
  374. using Unity.Mathematics;
  375.  
  376. [BurstCompile(CompileSynchronously = true)]
  377. struct ChunkJob : IJob
  378. {
  379.     public NativeList<float3> vertices;
  380.     public NativeList<int> triangles;
  381.     public NativeList<float2> uvs;
  382.  
  383.     [ReadOnly] public NativeArray<int3> faceDirections;
  384.     [ReadOnly] public NativeArray<float2> uvCordinates;
  385.     [ReadOnly] public NativeArray<int3> faceVertices;
  386.  
  387.     [ReadOnly] public int maxVoxelHeight;
  388.  
  389.     //Neighbouring chunks
  390.     [ReadOnly] public NativeArray<int> thisChunkData;
  391.     [ReadOnly] public NativeArray<int> leftChunkData;
  392.     [ReadOnly] public NativeArray<int> rightChunkData;
  393.     [ReadOnly] public NativeArray<int> frontChunkData;
  394.     [ReadOnly] public NativeArray<int> backChunkData;
  395.  
  396.     public void Execute()
  397.     {
  398.         int width = 16;
  399.         int height = maxVoxelHeight;
  400.         int depth = 16;
  401.  
  402.         for (int x = 0; x < width; x++)
  403.         {
  404.             for (int y = 0; y < height; y++)
  405.             {
  406.                 for (int z = 0; z < depth; z++)
  407.                 {
  408.                     if (thisChunkData[CalculateVoxelIndex(x, y, z)] == 1)
  409.                     {
  410.                         AddVoxel(x, y, z, vertices, triangles, uvs);
  411.                     }
  412.                 }
  413.             }
  414.         }
  415.     }
  416.  
  417.     private void AddVoxel(int x, int y, int z, NativeList<float3> vertices, NativeList<int> triangles, NativeList<float2> uvs)
  418.     {
  419.         for (int i = 0; i < 6; i++)
  420.         {
  421.             if (IsFaceVisible(x, y, z, i))
  422.             {
  423.                 AddQuad(new int3(x, y, z), i, vertices, triangles, uvs);
  424.             }
  425.         }
  426.     }
  427.  
  428.     private void AddQuad(int3 quadPos, int i, NativeList<float3> vertices, NativeList<int> triangles, NativeList<float2> uvs)
  429.     {
  430.         int vertCount = vertices.Length;
  431.  
  432.         NativeArray<float3> verts = new NativeArray<float3>(4, Allocator.Temp);
  433.  
  434.         for (int j = 0; j < 4; j++)
  435.         {
  436.             verts[j] = faceVertices[(i * 4) + j] + quadPos;
  437.         }
  438.  
  439.         vertices.AddRange(verts);
  440.  
  441.         NativeArray<int> tris = new NativeArray<int>(6, Allocator.Temp);
  442.  
  443.         tris[0] = vertCount;
  444.         tris[1] = vertCount + 1;
  445.         tris[2] = vertCount + 3;
  446.         tris[3] = vertCount + 3;
  447.         tris[4] = vertCount + 1;
  448.         tris[5] = vertCount + 2;
  449.  
  450.         triangles.AddRange(tris);
  451.  
  452.         float2 bottomLeft = uvCordinates[i];
  453.  
  454.         NativeArray<float2> uv = new NativeArray<float2>(4, Allocator.Temp);
  455.  
  456.         uv[0] = bottomLeft + new float2(.5f, 0);
  457.         uv[1] = bottomLeft + new float2(.5f, .5f);
  458.         uv[2] = bottomLeft + new float2(0, .5f);
  459.         uv[3] = bottomLeft;
  460.  
  461.         uvs.AddRange(uv);
  462.     }
  463.  
  464.     private bool IsFaceVisible(int x, int y, int z, int faceIndex)
  465.     {
  466.         int3 direction = faceDirections[faceIndex];
  467.         int3 neighbor = new int3(x + direction.x, y + direction.y, z + direction.z);
  468.  
  469.         if (neighbor.y < 0 || neighbor.y >= maxVoxelHeight)
  470.             return false;
  471.  
  472.         if (neighbor.x < 0)
  473.             return leftChunkData[CalculateVoxelIndex(15, neighbor.y, neighbor.z)] == 0;
  474.  
  475.         if (neighbor.x >= 16)
  476.             return rightChunkData[CalculateVoxelIndex(0, neighbor.y, neighbor.z)] == 0;
  477.  
  478.         if (neighbor.z < 0)
  479.             return backChunkData[CalculateVoxelIndex(neighbor.x, neighbor.y, 15)] == 0;
  480.  
  481.         if (neighbor.z >= 16)
  482.             return frontChunkData[CalculateVoxelIndex(neighbor.x, neighbor.y, 0)] == 0;
  483.  
  484.         return thisChunkData[CalculateVoxelIndex(neighbor.x, neighbor.y, neighbor.z)] == 0;
  485.     }
  486.  
  487.     public int CalculateVoxelIndex(int x, int y, int z)
  488.     {
  489.         return x * (maxVoxelHeight * 16) + y * 16 + z;
  490.     }
  491. }
  492. using Unity.Collections;
  493. using UnityEngine;
  494. using Unity.Mathematics;
  495.  
  496. public class BlockBreakingAndPlacing : MonoBehaviour
  497. {
  498.     public float maxReach;
  499.     public LayerMask mask;
  500.  
  501.     RaycastHit hit;
  502.     GameObject cam;
  503.  
  504.     private void Start()
  505.     {
  506.         cam = GameObject.Find("PlayerCamera");
  507.     }
  508.  
  509.     private void Update()
  510.     {
  511.         if (Input.GetMouseButtonDown(0))
  512.         {
  513.             if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, maxReach, mask))
  514.             {
  515.                 ChunkGenerator chunkGen = GameObject.Find("ChunkGenerator").GetComponent<ChunkGenerator>();
  516.  
  517.                 int2 coordinates = new int2((int)hit.collider.transform.position.x + 8, (int)hit.collider.transform.position.z + 8);
  518.                 NativeArray<int> voxelValues = chunkGen.chunkDataMap[coordinates];
  519.  
  520.                 int x = (int)(Mathf.Abs(hit.collider.transform.position.x - Mathf.Round(hit.point.x - .5f)));
  521.                 int y = Mathf.Abs(Mathf.RoundToInt(hit.point.y)) - 1;
  522.                 int z = (int)(Mathf.Abs(hit.collider.transform.position.z - Mathf.Round(hit.point.z - .5f)));
  523.  
  524.                 voxelValues[ChunkGenerator.CalculateVoxelIndex(x, y, z)] = 0;
  525.  
  526.                 Mesh mesh = chunkGen.CreateChunkMesh(new Vector2Int(coordinates.x, coordinates.y), voxelValues);
  527.                 hit.collider.GetComponent<MeshFilter>().mesh = mesh;
  528.  
  529.                 //Reset collider
  530.                 hit.collider.GetComponent<MeshCollider>().sharedMesh = null;
  531.                 hit.collider.GetComponent<MeshCollider>().sharedMesh = mesh;
  532.  
  533.             }
  534.         }
  535.  
  536.         if (Input.GetMouseButtonDown(1))
  537.         {
  538.             if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, maxReach, mask))
  539.             {
  540.                 ChunkGenerator chunkGen = GameObject.Find("ChunkGenerator").GetComponent<ChunkGenerator>();
  541.  
  542.                 int2 coordinates = new int2((int)hit.collider.transform.position.x + 8, (int)hit.collider.transform.position.z + 8);
  543.                 NativeArray<int> voxelValues = chunkGen.chunkDataMap[coordinates];
  544.  
  545.                 int x = (int)(Mathf.Abs(hit.collider.transform.position.x - Mathf.Round(hit.point.x - .5f)));
  546.                 int y = Mathf.Abs(Mathf.RoundToInt(hit.point.y));
  547.                 int z = (int)(Mathf.Abs(hit.collider.transform.position.z - Mathf.Round(hit.point.z - .5f)));
  548.  
  549.                 voxelValues[ChunkGenerator.CalculateVoxelIndex(x, y, z)] = 1;
  550.  
  551.                 Mesh mesh = chunkGen.CreateChunkMesh(new Vector2Int(coordinates.x, coordinates.y), voxelValues);
  552.                 hit.collider.GetComponent<MeshFilter>().mesh = mesh;
  553.  
  554.                 //Reset collider
  555.                 hit.collider.GetComponent<MeshCollider>().sharedMesh = null;
  556.                 hit.collider.GetComponent<MeshCollider>().sharedMesh = mesh;
  557.  
  558.             }
  559.         }
  560.     }
  561. }
  562. using System;
  563. using System.Collections.Generic;
  564. using UnityEngine;
  565.  
  566. public class EndlessTerrain : MonoBehaviour
  567. {
  568.     public float maxViewDst;
  569.     public float colliderRange;
  570.     public Transform viewer;
  571.  
  572.     public static Vector2 viewerPosition;
  573.     int chunksVisibleInViewDst;
  574.  
  575.     Dictionary<Vector2, TerrainChunk> chunkDictionary = new Dictionary<Vector2, TerrainChunk>();
  576.     List<TerrainChunk> chunksVisibleLastUpdate = new List<TerrainChunk>();
  577.  
  578.     void Start()
  579.     {
  580.         chunksVisibleInViewDst = Mathf.RoundToInt(maxViewDst / 16);
  581.     }
  582.  
  583.     void Update()
  584.     {
  585.         viewerPosition = new Vector2(viewer.position.x, viewer.position.z);
  586.         UpdateVisibleChunks();
  587.     }
  588.  
  589.     void UpdateVisibleChunks()
  590.     {
  591.         for (int i = 0; i < chunksVisibleLastUpdate.Count; i++)
  592.         {
  593.             chunksVisibleLastUpdate[i].chunkObject.SetActive(false);
  594.         }
  595.  
  596.         chunksVisibleLastUpdate.Clear();
  597.  
  598.         int currentChunkCoordX = (int)Mathf.Round(viewerPosition.x / 16);
  599.         int currentChunkCoordY = (int)Mathf.Round(viewerPosition.y / 16);
  600.  
  601.         for (int yOffset = -chunksVisibleInViewDst; yOffset <= chunksVisibleInViewDst; yOffset++) //Loops through all the current chunks
  602.         {
  603.             for (int xOffset = -chunksVisibleInViewDst; xOffset <= chunksVisibleInViewDst; xOffset++)
  604.             {
  605.                 Vector2Int viewedChunkCoord = new Vector2Int(currentChunkCoordX + xOffset, currentChunkCoordY + yOffset);
  606.  
  607.                 if (chunkDictionary.ContainsKey(viewedChunkCoord)) //Checks if a chunk with the correct cordinates has been loaded previously
  608.                 {
  609.                     TerrainChunk viewedChunk = chunkDictionary[viewedChunkCoord];
  610.  
  611.                     viewedChunk.UpdateTerrainChunk();
  612.  
  613.                     if (viewedChunk.IsVisible())
  614.                     {
  615.                         chunksVisibleLastUpdate.Add(viewedChunk);
  616.                     }
  617.                 }
  618.                 else
  619.                 {
  620.                     chunkDictionary.Add(viewedChunkCoord, new TerrainChunk(viewedChunkCoord, transform, maxViewDst, colliderRange));
  621.                 }
  622.             }
  623.         }
  624.     }
  625.  
  626.     public class TerrainChunk
  627.     {
  628.         public GameObject chunkObject;
  629.  
  630.         ChunkGenerator chunkGen;
  631.  
  632.         Vector2Int position;
  633.         Bounds bounds;
  634.  
  635.         float maxViewDst;
  636.         float colliderRange;
  637.  
  638.         bool hasCollider;
  639.  
  640.         public TerrainChunk(Vector2Int coord, Transform parent, float maxViewDst, float colliderRange)
  641.         {
  642.             position = coord * 16;
  643.             bounds = new Bounds(new Vector2(position.x, position.y), Vector2.one * 16);        
  644.  
  645.             chunkGen = GameObject.Find("ChunkGenerator").GetComponent<ChunkGenerator>();
  646.  
  647.             chunkObject = chunkGen.CreateChunkObject(position);
  648.             chunkObject.transform.position = new Vector3(position.x - 8, 0, position.y - 8);
  649.  
  650.             chunkObject.transform.parent = parent;
  651.             chunkObject.SetActive(false);
  652.  
  653.             this.maxViewDst = maxViewDst;
  654.             this.colliderRange = colliderRange;
  655.         }
  656.  
  657.         public void UpdateTerrainChunk()
  658.         {
  659.             float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
  660.  
  661.             if(viewerDstFromNearestEdge < colliderRange && !hasCollider)
  662.             {
  663.                 chunkObject.AddComponent<MeshCollider>();
  664.                 hasCollider = true;
  665.             }
  666.  
  667.             bool visible = viewerDstFromNearestEdge <= maxViewDst; //Checks if the chunk is too far away from the player, if so it deactivates it
  668.  
  669.             chunkObject.SetActive(visible);
  670.         }
  671.  
  672.         public bool IsVisible()
  673.         {
  674.             return chunkObject.activeSelf;
  675.         }
  676.     }
  677. }
  678.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement