Skip to content
Snippets Groups Projects
TerrainGenerator.cs 3.64 KiB
Newer Older
Chang, Ryan's avatar
Chang, Ryan committed
using System.Threading;
Chang, Ryan's avatar
Chang, Ryan committed
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
Chang, Ryan's avatar
Chang, Ryan committed

[System.Serializable]
public struct Octave
{
    public float amplitude;
    public float frequency;
    public NoiseType type;
}

[System.Serializable]
public enum NoiseType
{
    MathfPerlin,
    MathematicsPerlin,
    Simplex,
    Celluar
Chang, Ryan's avatar
Chang, Ryan committed
}

public class TerrainGenerator : MonoBehaviour
{
Chang, Ryan's avatar
Chang, Ryan committed
    [Header("User settings")]
    public List<Octave> octaves;

    [Tooltip("The seed of the generation.")]
    public Vector2 crawlStartPosition;

    public bool generateNewSeed = true;

    public bool refresh;
Chang, Ryan's avatar
Chang, Ryan committed

    [Tooltip("How fine grain the generated terrain will be. " +
        "Larger values = more precise. Recommended value is 513.")]
Chang, Ryan's avatar
Chang, Ryan committed
    public int samples = 513;
Chang, Ryan's avatar
Chang, Ryan committed

Chang, Ryan's avatar
Chang, Ryan committed
    [Header("Autogenerated values")]
    [Tooltip("Which terrain grid are we on right now?")]
    public Vector2Int currentGridPosition;

    [Tooltip("Dictionary of previously loaded terrains.")]
Chang, Ryan's avatar
Chang, Ryan committed
    public Dictionary<Vector2Int, TerrainData> previouslyLoaded = new();
Chang, Ryan's avatar
Chang, Ryan committed

    /// <summary>
Chang, Ryan's avatar
Chang, Ryan committed
    /// Threads used for generating the neighboring and current terrains.
Chang, Ryan's avatar
Chang, Ryan committed
    /// </summary>
Chang, Ryan's avatar
Chang, Ryan committed
    private Thread[] generationThreads = new Thread[9];
Chang, Ryan's avatar
Chang, Ryan committed

Chang, Ryan's avatar
Chang, Ryan committed
    private List<TerrainGenThread> generators = new();

    private void ThreadGenerationFinished(TerrainGenThread genThread)
Chang, Ryan's avatar
Chang, Ryan committed
    {
Chang, Ryan's avatar
Chang, Ryan committed
        genThread.TerrainData.SetHeights(0, 0, genThread.GetHeights());

        GameObject obj = Terrain.CreateTerrainGameObject(genThread.TerrainData);
        obj.name = genThread.InitialCrawlPosition.ToString() + "Terrain";
        obj.transform.SetParent(transform, false);
        Vector3 offset = new Vector3(genThread.GridPosition.x, 0, genThread.GridPosition.y) *
            genThread.TerrainData.size.x;
        obj.transform.position += offset;
    }

    private void GenerateThread(Vector2 crawlPos, Vector2Int gridPos, ref Thread thread,
        ref List<TerrainGenThread> genThreads, bool forceRefresh)
    {
        if (!previouslyLoaded.ContainsKey(gridPos) || forceRefresh)
Chang, Ryan's avatar
Chang, Ryan committed
        {
Chang, Ryan's avatar
Chang, Ryan committed
            TerrainData data = Instantiate(Resources.Load<TerrainData>("Template"));
            TerrainGenThread genThread = new(crawlPos, gridPos, octaves, samples, data);
            genThreads.Add(genThread);
            ThreadStart starter = new ThreadStart(genThread.Generate);
            thread = new Thread(starter);
Chang, Ryan's avatar
Chang, Ryan committed
            previouslyLoaded[gridPos] = data;
            thread.Start();
Chang, Ryan's avatar
Chang, Ryan committed
        }
Chang, Ryan's avatar
Chang, Ryan committed
    }

Chang, Ryan's avatar
Chang, Ryan committed
    public virtual void GenerateSurronding(Vector2 initCrawlPos, bool forceRefresh = false)
Chang, Ryan's avatar
Chang, Ryan committed
    {
Chang, Ryan's avatar
Chang, Ryan committed
        int count = 0;
        for (int i = -1; i <= 1; i++)
        {
            for (int j = 1; j >= -1; j--)
            {
                GenerateThread(initCrawlPos + new Vector2(i, j),
                    currentGridPosition + new Vector2Int(i, j),
                    ref generationThreads[count], ref generators,
                    forceRefresh);
                count++;
            }
        }
Chang, Ryan's avatar
Chang, Ryan committed
        foreach (var thread in generationThreads)
Chang, Ryan's avatar
Chang, Ryan committed
            if (thread != null)
            {
                thread.Join(); 
            }
Chang, Ryan's avatar
Chang, Ryan committed

Chang, Ryan's avatar
Chang, Ryan committed
        foreach (var genThread in generators)
Chang, Ryan's avatar
Chang, Ryan committed
            if (genThread != null)
Chang, Ryan's avatar
Chang, Ryan committed
                ThreadGenerationFinished(genThread); 
Chang, Ryan's avatar
Chang, Ryan committed
        generators.Clear();
Chang, Ryan's avatar
Chang, Ryan committed
    private void Start()
    {
Chang, Ryan's avatar
Chang, Ryan committed
        GenerateSurronding(crawlStartPosition);
Chang, Ryan's avatar
Chang, Ryan committed
    }

    private void Update()
    {
Chang, Ryan's avatar
Chang, Ryan committed
        if (refresh)
        {
            refresh = false;

            foreach (Transform child in transform)
                Destroy(child.gameObject);

            GenerateSurronding(crawlStartPosition, true);
        }
Chang, Ryan's avatar
Chang, Ryan committed
    }
}