ChunkTerrainGenerator.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using KairoEngine.Core;
  5. using KairoEngine.Chunks;
  6. using KairoEngine.NoiseUtilities;
  7. using Sirenix.OdinInspector;
  8. using UniRx;
  9. namespace KairoEngine.TerrainEngine
  10. {
  11. [HideMonoScript]
  12. public class ChunkTerrainGenerator : MonoBehaviour
  13. {
  14. public MarchingCubes3 marchingCubes3;
  15. public MarchingCubes2 marchingCubes2;
  16. public Vector3Int chunkSize = new Vector3Int(16, 16, 16);
  17. public Vector3Int chunkLimit = new Vector3Int(2, 1, 2);
  18. //public float noiseMultiplier = 1.5f;
  19. [InlineProperty, HideLabel, FoldoutGroup("Noise Generator")] public NoiseCombinator noiseCombinator = new NoiseCombinator();
  20. [HideInInspector] public ChunkSystem<BlockBase> chunkSystem;
  21. [Button("Generate"), ButtonGroup("Buttons")]
  22. void CreateChunks()
  23. {
  24. if(noiseCombinator == null)
  25. {
  26. Debug.LogError("Missing Noise Combinator", this.gameObject);
  27. return;
  28. }
  29. DestroyTerrain();
  30. Debug.Log("Starting chunk generation");
  31. chunkSystem = new ChunkSystem<BlockBase>(chunkSize, true);
  32. for (int x = 0; x < chunkLimit.x; x++) {
  33. for (int z = 0; z < chunkLimit.z; z++) {
  34. for (int y = 0; y < chunkLimit.y; y++) {
  35. Vector3Int chunkPos = new Vector3Int(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z);
  36. chunkSystem.CreateChunk(chunkPos, (Chunk<BlockBase> c, Vector3Int pos) => new BlockBase(0, 0));
  37. GenerateChunkTerrain(chunkPos);
  38. }
  39. }
  40. }
  41. for (int x = 0; x < chunkLimit.x; x++) {
  42. for (int z = 0; z < chunkLimit.z; z++) {
  43. for (int y = 0; y < chunkLimit.y; y++) {
  44. Vector3Int chunkPos = new Vector3Int(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z);
  45. if(marchingCubes3 != null) marchingCubes3.Generate(chunkSystem, chunkPos);
  46. else if(marchingCubes2 != null) marchingCubes2.Generate(chunkSystem, chunkPos);
  47. }
  48. }
  49. }
  50. #if UNITY_EDITOR
  51. UpdateEditor ();
  52. #endif
  53. }
  54. void GenerateChunkTerrain(Vector3Int initialPos)
  55. {
  56. float width = (float)(chunkLimit.x * chunkSize.x);
  57. float height = (float)(chunkLimit.y * chunkSize.y);
  58. float length = (float)(chunkLimit.z * chunkSize.z);
  59. for (int x = 0; x < chunkSize.x; x++) {
  60. for (int z = 0; z < chunkSize.z; z++) {
  61. for (int y = 0; y < chunkSize.y; y++) {
  62. // Get a terrain height using regular old Perlin noise.
  63. Vector3Int pos = initialPos + new Vector3Int(x, y, z);
  64. // Old example noise:
  65. //float thisHeight = height * Mathf.PerlinNoise((float)pos.x / width * noiseMultiplier + 0.001f, (float)pos.z / length * noiseMultiplier + 0.001f);
  66. float thisHeight = height * noiseCombinator.SamplePoint((float)pos.x / width, (float)pos.z / length);
  67. uint code = CalculateCode(thisHeight, height);
  68. BlockBase block = new BlockBase(code, (uint)Mathf.FloorToInt(thisHeight));
  69. chunkSystem.SetBlock(pos, block);
  70. }
  71. }
  72. }
  73. }
  74. void UpdateEditor ()
  75. {
  76. Timer.ExecuteRealTime(50, () => {
  77. if(marchingCubes3 != null)
  78. {
  79. marchingCubes3.UpdateFinishedJobs();
  80. if(!marchingCubes3.IsGeneratorDone()) UpdateEditor();
  81. }
  82. });
  83. }
  84. [Button("Destroy"), ButtonGroup("Buttons")]
  85. private void DestroyTerrain()
  86. {
  87. var childTransforms = this.gameObject.transform.GetComponentsInChildren<Transform>();
  88. if(childTransforms.Length > 0) Debug.Log($"Destroying {childTransforms.Length - 1} terrain objects");
  89. for (int i = 0; i < childTransforms.Length; i++)
  90. {
  91. if(childTransforms[i] == this.transform) continue;
  92. #if UNITY_EDITOR
  93. DestroyImmediate(childTransforms[i].gameObject);
  94. #else
  95. Destroy(childTransforms[i].gameObject);
  96. #endif
  97. }
  98. }
  99. private uint CalculateCode(float height, float maxHeight)
  100. {
  101. var value = height/maxHeight;
  102. if(value > 0.8) return 2;
  103. else if(value > 0.4) return 1;
  104. else return 0;
  105. }
  106. }
  107. }