using System.Collections; using System.Collections.Generic; using UnityEngine; using KairoEngine.Core; using KairoEngine.Chunks; using KairoEngine.NoiseUtilities; using Sirenix.OdinInspector; using UniRx; namespace KairoEngine.TerrainEngine { [HideMonoScript] public class ChunkTerrainGenerator : MonoBehaviour { public MarchingCubes3 marchingCubes3; public MarchingCubes2 marchingCubes2; public Vector3Int chunkSize = new Vector3Int(16, 16, 16); public Vector3Int chunkLimit = new Vector3Int(2, 1, 2); //public float noiseMultiplier = 1.5f; [InlineProperty, HideLabel, FoldoutGroup("Noise Generator")] public NoiseCombinator noiseCombinator = new NoiseCombinator(); [HideInInspector] public ChunkSystem chunkSystem; [Button("Generate"), ButtonGroup("Buttons")] void CreateChunks() { if(noiseCombinator == null) { Debug.LogError("Missing Noise Combinator", this.gameObject); return; } DestroyTerrain(); Debug.Log("Starting chunk generation"); chunkSystem = new ChunkSystem(chunkSize, true); for (int x = 0; x < chunkLimit.x; x++) { for (int z = 0; z < chunkLimit.z; z++) { for (int y = 0; y < chunkLimit.y; y++) { Vector3Int chunkPos = new Vector3Int(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z); chunkSystem.CreateChunk(chunkPos, (Chunk c, Vector3Int pos) => new BlockBase(0, 0)); GenerateChunkTerrain(chunkPos); } } } for (int x = 0; x < chunkLimit.x; x++) { for (int z = 0; z < chunkLimit.z; z++) { for (int y = 0; y < chunkLimit.y; y++) { Vector3Int chunkPos = new Vector3Int(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z); if(marchingCubes3 != null) marchingCubes3.Generate(chunkSystem, chunkPos); else if(marchingCubes2 != null) marchingCubes2.Generate(chunkSystem, chunkPos); } } } #if UNITY_EDITOR UpdateEditor (); #endif } void GenerateChunkTerrain(Vector3Int initialPos) { float width = (float)(chunkLimit.x * chunkSize.x); float height = (float)(chunkLimit.y * chunkSize.y); float length = (float)(chunkLimit.z * chunkSize.z); for (int x = 0; x < chunkSize.x; x++) { for (int z = 0; z < chunkSize.z; z++) { for (int y = 0; y < chunkSize.y; y++) { // Get a terrain height using regular old Perlin noise. Vector3Int pos = initialPos + new Vector3Int(x, y, z); // Old example noise: //float thisHeight = height * Mathf.PerlinNoise((float)pos.x / width * noiseMultiplier + 0.001f, (float)pos.z / length * noiseMultiplier + 0.001f); float thisHeight = height * noiseCombinator.SamplePoint((float)pos.x / width, (float)pos.z / length); uint code = CalculateCode(thisHeight, height); BlockBase block = new BlockBase(code, (uint)Mathf.FloorToInt(thisHeight)); chunkSystem.SetBlock(pos, block); } } } } void UpdateEditor () { Timer.ExecuteRealTime(50, () => { if(marchingCubes3 != null) { marchingCubes3.UpdateFinishedJobs(); if(!marchingCubes3.IsGeneratorDone()) UpdateEditor(); } }); } [Button("Destroy"), ButtonGroup("Buttons")] private void DestroyTerrain() { var childTransforms = this.gameObject.transform.GetComponentsInChildren(); if(childTransforms.Length > 0) Debug.Log($"Destroying {childTransforms.Length - 1} terrain objects"); for (int i = 0; i < childTransforms.Length; i++) { if(childTransforms[i] == this.transform) continue; #if UNITY_EDITOR DestroyImmediate(childTransforms[i].gameObject); #else Destroy(childTransforms[i].gameObject); #endif } } private uint CalculateCode(float height, float maxHeight) { var value = height/maxHeight; if(value > 0.8) return 2; else if(value > 0.4) return 1; else return 0; } } }