miepzerino
2025-04-03 a34c1ebe91bdf70510fac0b388b00b3c05a82c55
Assets/Scripts/GenerateTileMap.cs
@@ -5,43 +5,44 @@
using UnityEngine;
using UnityEngine.Tilemaps;
using UnityEngine.UIElements;
using static UnityEditor.Progress;
[Serializable]
public class Ore
{
    public string name;
    /// <summary>
    /// The lower the numer the higher the amount of ores that will spawn
    /// Higher number means less ore
    /// </summary>
    [Tooltip("The lower the numer the higher the amount of ores that will spawn. Higher number means less ore.")]
    [Range(1, 100000)]
    public int weight;
    /// <summary>
    /// The lower the number the more dense the ore will spawn (big clusters
    /// Higher number means little clusters (more spread)
    /// </summary>
    [Tooltip("The lower the number the more dense the ore will spawn (big clusters. Higher number means little clusters (more spread).")]
    [Range(10, 100000)]
    public int clusterWeight;
    public RuleTile tile;
    public int maxSpawnHeight;
    public int minSpawnHeight;
}
//[Serializable]
//public class Ore
//{
//    public string name;
//    /// <summary>
//    /// The lower the numer the higher the amount of ores that will spawn
//    /// Higher number means less ore
//    /// </summary>
//    [Tooltip("The lower the numer the higher the amount of ores that will spawn. Higher number means less ore.")]
//    [Range(1, 100000)]
//    public int weight;
//    /// <summary>
//    /// The lower the number the more dense the ore will spawn (big clusters
//    /// Higher number means little clusters (more spread)
//    /// </summary>
//    [Tooltip("The lower the number the more dense the ore will spawn (big clusters. Higher number means little clusters (more spread).")]
//    [Range(10, 100000)]
//    public int clusterWeight;
//    public CustomRuleTile tile;
//    public int maxSpawnHeight;
//    public int minSpawnHeight;
//}
public class GenerateTileMap : MonoBehaviour
{
    public int? seed;
    public int maxWidth = 256;
    public int maxHeight = 384;
    public int maxGroundHeight = 256;
    public static int maxWidth = 256;
    public static int maxDepth = 384;
    public static int groundDepth = 256;
    private float scale;
    private float offsetX;
    private float offsetY;
    Tilemap tilemap;
    public RuleTile forestRuleTile;
    public CustomRuleTile forestRuleTile;
    public TileBase borderTile;
    public List<Ore> ores;
    private List<Generateable> generateables;
    //public List<TileBase> tiles;
    private void Awake()
@@ -56,6 +57,43 @@
        }
        SetSettingsFromSeed(seed.Value);
        // Position adjusted to center horizontally, but align top at y=0
        transform.position = new Vector3((maxWidth / 2) * -1, -1, transform.position.z);
        LoadGenerateablesFromResources();
    }
    private void LoadGenerateablesFromResources()
    {
        // Clear existing siblings
        forestRuleTile.siblings.Clear();
        // Load all Item prefabs from the "Resources/Items" folder
        GameObject[] generateablePrefabs = Resources.LoadAll<GameObject>("Generateable");
        generateables = new List<Generateable>();
        foreach (GameObject prefab in generateablePrefabs)
        {
            Generateable generateable = prefab.GetComponent<Generateable>();
            if (generateable != null)
            {
                generateable.tile = ScriptableObject.CreateInstance<CustomRuleTile>();
                generateable.tile.m_DefaultGameObject = prefab;
                generateable.tile.m_DefaultSprite = generateable.sprite;
                generateables.Add(generateable);
                forestRuleTile.siblings.Add(generateable.tile);
            }
            else
            {
                Debug.LogWarning($"Prefab {prefab.name} does not have an Item component");
            }
        }
        GenerateableDatabase.Instance.InitializeFromGenerateables(generateables);
        if (generateables.Count == 0)
        {
            Debug.LogWarning("No items found in Resources/Items folder");
        }
    }
    public void SetSettingsFromSeed(int seed)
@@ -86,12 +124,26 @@
    public IEnumerator GenerateTiles(Action finishedCallback, List<Vector3Int> destroyedTiles)
    {
        // generate ground
        yield return CreateGroundLayer(destroyedTiles);
        if (generateables != null)
        {
            yield return GenerateOreClusters(destroyedTiles);
        }
        // generate borders
        yield return GenerateBorders();
        finishedCallback();
    }
    private IEnumerator CreateGroundLayer(List<Vector3Int> destroyedTiles)
    {
        for (int x = 1; x < maxWidth; x++)
        {
            for (int y = 1; y < maxGroundHeight; y++)
            for (int y = -1; y > -groundDepth; y--)
            {
                float xPerlin = ((float)x / maxWidth) * scale + offsetX;
                float yPerlin = ((float)y / maxHeight) * scale + offsetY;
                float yPerlin = ((float)Mathf.Abs(y) / maxDepth) * scale + offsetY;
                float perlinNoise = Mathf.PerlinNoise(xPerlin, yPerlin);
                if (perlinNoise <= 0.7f)
@@ -111,58 +163,110 @@
                yield return null;
            }
        }
    }
        if (ores != null)
    private IEnumerator GenerateOreClusters(List<Vector3Int> destroyedTiles)
    {
        foreach (Generateable generateable in generateables)
        {
            foreach (Ore ore in ores)
            // Convert spawn heights to negative values if they aren't already
            int maxY = -Mathf.Abs(generateable.maxSpawnHeight);
            int minY = -Mathf.Abs(generateable.minSpawnHeight);
            Debug.Log($"Generating {generateable.name} between Y: {minY} - {maxY}");
            for (int x = 0; x < maxWidth; x++)
            {
                for (int x = 0; x < maxWidth; x++)
                for (int y = maxY; y > minY; y--)
                {
                    for (int y = ore.minSpawnHeight; y < ore.maxSpawnHeight; y++)
                    {
                        float xPerlin = ((float)x / maxWidth) * (float)ore.clusterWeight + offsetX;
                        float yPerlin = ((float)y / maxHeight) * (float)ore.clusterWeight + offsetY;
                        float perlinNoise = Mathf.PerlinNoise(xPerlin, yPerlin);
                    float xPerlin = ((float)x / maxWidth) * (float)generateable.clusterWeight + offsetX;
                    float yPerlin = ((float)Mathf.Abs(y) / maxDepth) * (float)generateable.clusterWeight + offsetY;
                    float perlinNoise = Mathf.PerlinNoise(xPerlin, yPerlin);
                        if (perlinNoise <= (1f / (float)ore.weight))
                    if (perlinNoise <= (1f / (float)generateable.weight))
                    {
                        Vector3Int tileSpawnCoord = new Vector3Int(x, y);
                        if (!destroyedTiles.Contains(tileSpawnCoord) && tilemap.HasTile(tileSpawnCoord))
                        {
                            Vector3Int tileSpawnCoord = new Vector3Int(x, y);
                            if (!destroyedTiles.Contains(tileSpawnCoord) && tilemap.HasTile(tileSpawnCoord))
                            // Check potential cluster size before placing
                            int clusterSize = CountPotentialClusterSize(x, y, generateable.weight, generateable.clusterWeight);
                            if (clusterSize >= generateable.minClusterSize)
                            {
                                tilemap.SetTile(tileSpawnCoord, ore.tile);
                                tilemap.SetTile(tileSpawnCoord, generateable.tile);
                            }
                            //tilemap.SetTile(tileSpawnCoord, generateable.tile);
                        }
                    }
                    // Update UI every 8 lines
                    if ((x % 8) == 0)
                    {
                        yield return null;
                    }
                }
                // Update UI every 8 lines
                if ((x % 8) == 0)
                {
                    yield return null;
                }
            }
        }
    }
        // generate borders
    private IEnumerator GenerateBorders()
    {
        // Vertical borders (going up from underground to sky)
        for (int x = 0; x <= maxWidth; x += maxWidth)
        {
            for (int y = 0; y <= maxHeight; y++)
            for (int y = -groundDepth; y <= maxDepth - groundDepth; y++)
            {
                tilemap.SetTile(new Vector3Int(x, y), borderTile);
            }
        }
        yield return null;
        for (int y = 0; y <= maxHeight; y += maxHeight)
        // Horizontal borders (at bottom and sky level)
        for (int y = -groundDepth; y <= maxDepth - groundDepth; y += maxDepth)
        {
            for (int x = 1; x <= maxWidth; x++)
            {
                tilemap.SetTile(new Vector3Int(x, y), borderTile);
            }
        }
        yield return null;
        finishedCallback();
    }
    private int CountPotentialClusterSize(int startX, int startY, int weight, int clusterWeight)
    {
        int size = 0;
        Queue<Vector2Int> toCheck = new Queue<Vector2Int>();
        HashSet<Vector2Int> checked_positions = new HashSet<Vector2Int>();
        toCheck.Enqueue(new Vector2Int(startX, startY));
        checked_positions.Add(new Vector2Int(startX, startY));
        while (toCheck.Count > 0)
        {
            Vector2Int current = toCheck.Dequeue();
            size++;
            // Check all 8 neighboring tiles
            for (int dx = -1; dx <= 1; dx++)
            {
                for (int dy = -1; dy <= 1; dy++)
                {
                    if (dx == 0 && dy == 0) continue;
                    Vector2Int neighbor = new Vector2Int(current.x + dx, current.y + dy);
                    if (checked_positions.Contains(neighbor)) continue;
                    float xPerlin = ((float)neighbor.x / maxWidth) * clusterWeight + offsetX;
                    float yPerlin = ((float)Mathf.Abs(neighbor.y) / maxDepth) * clusterWeight + offsetY;
                    float perlinNoise = Mathf.PerlinNoise(xPerlin, yPerlin);
                    if (perlinNoise <= (1f / (float)weight))
                    {
                        toCheck.Enqueue(neighbor);
                        checked_positions.Add(neighbor);
                    }
                }
            }
        }
        return size;
    }
}