我可以帮你翻译这段文本。

我正在开发一个Unity中的地形生成系统,使用了一个基于高度的离散网格系统。系统分为三个部分:数据、生成和可视化。

数据部分使用一个二维矩阵来存储每个网格单元的高度值,每个值都是一个整数。这个矩阵是系统的唯一真实来源。

生成部分使用Perlin噪声来生成高度分布,通过对噪声进行缩放来得到连续的高度分布。然后,我使用一个基于邻居的平滑系统来去除噪声并得到自然的丘陵形状。

可视化部分使用多个Tilemap来表示不同的高度层,每个高度层都有自己的Tilemap和Tile类型。每个网格单元都会根据其高度在相应的Tilemap中绘制。

这个项目使用了一个等距网格,并且所有的Sprite都已经适应了这个系统。Sprite的大小是19x19像素,但它们是等距的Sprite(不是完全的正方形),因为它们的部分区域是空的,以形成等距的形状。Pixels Per Unit是32,Pivot是居中的。

在调试过程中,我遇到了一个问题:Grid的缩放和Sprite的可视化不匹配。Grid的Cell Size是(0.5,0.25,1),但实际上Sprite的高度不是完全匹配这个配置。这个问题导致高度层在垂直轴上看起来不完全对齐。

为了解决这个问题,我手动调整了Sprite的可视化高度,直到找到一个值,它可以正确匹配当前的艺术风格(约为0.3125个单位/高度层)。这个调整不是来自Grid的直接公式,而是基于Sprite在屏幕上的外观进行的经验性调整。

在这个阶段,系统在可视化层面上是正确的:地形生成是连贯的,高度层是正确地表示出来的,结果是稳定的。

然而,我对系统的总体架构有几个疑问:

  • 高度值依赖于Grid和Sprite之间的手动调整。
  • 我正在使用多个Tilemap来表示不同的高度层。
  • 我还没有实现碰撞检测和基于高度的移动逻辑。
  • 我不确定这个方法是否能适应更高的高度层或世界复杂度。

目前,这个系统仅仅是生成和渲染系统,没有玩家交互或游戏规则。

我正在使用人工智能来支持开发,主要是为了避免早期的架构错误,并在构建系统时验证技术决策。

我想知道这个方法是否是可扩展的基础,是一个合适的等距系统,还是我应该从头开始设计一个新的架构。

以下是我的代码:

using UnityEngine;
using UnityEngine.Tilemaps;

public class GeneradorMapa : MonoBehaviour
{
    [SerializeField] private Tilemap tilemap0;
    [SerializeField] private Tilemap tilemap1;
    [SerializeField] private Tilemap tilemap2;
    [SerializeField] private Tilemap tilemap3;

    [SerializeField] private TileBase tileH0;
    [SerializeField] private TileBase tileH1;
    [SerializeField] private TileBase tileH2;
    [SerializeField] private TileBase tileH3;

    [SerializeField] private int ancho = 20;
    [SerializeField] private int alto = 20;

    private Celda[,] mapa;

    [Header("Generación de terreno")]
    [SerializeField] private int alturaMaxima = 3;
    [SerializeField] private int seed = 0;
    [SerializeField] private float suavizado;
    [SerializeField] private float unidadAltura = 0.3125f;

    [Header("Ruido")]
    [SerializeField] private float escalaRuido = 0.1f;

    private void Start()
    {
        AplicarOffsetsAltura();
        GenerarDatosMapa();
        SuavizarMapa();
        GenerarVisuales();
    }

    private void GenerarDatosMapa()
    {
        mapa = new Celda[ancho, alto];

        for (int x = 0; x < ancho; x++)
        {
            for (int y = 0; y < alto; y++)
            {
                mapa[x, y] = new Celda();

                float xCoord = x * escalaRuido;
                float yCoord = y * escalaRuido;

                float noise = Mathf.PerlinNoise(xCoord, yCoord);

                int altura = Mathf.FloorToInt(noise * alturaMaxima);

                mapa[x, y].altura = altura;
            }
        }
    }

    private void GenerarVisuales()
    {
        tilemap0.ClearAllTiles();
        tilemap1.ClearAllTiles();
        tilemap2.ClearAllTiles();
        tilemap3.ClearAllTiles();

        for (int x = 0; x < ancho; x++)
        {
            for (int y = 0; y < alto; y++)
            {
                int h = mapa[x, y].altura;
                Vector3Int pos = new Vector3Int(x, y, 0);

                if (h == 0)
                {
                    tilemap0.SetTile(pos, tileH0);
                }
                else if (h == 1)
                {
                    tilemap1.SetTile(pos, tileH1);
                }
                else if (h == 2)
                {
                    tilemap2.SetTile(pos, tileH2);
                }
                else
                {
                    tilemap3.SetTile(pos, tileH3);
                }
            }
        }
    }

    private void SuavizarMapa()
    {
        Celda[,] copia = new Celda[ancho, alto];

        for (int x = 0; x < ancho; x++)
        {
            for (int y = 0; y < alto; y++)
            {
                copia[x, y] = new Celda();
            }
        }

        for (int x = 0; x < ancho; x++)
        {
            for (int y = 0; y < alto; y++)
            {
                int suma = mapa[x, y].altura;
                int count = 1;

                if (x > 0)
                {
                    suma += mapa[x - 1, y].altura;
                    count++;
                }

                if (x < ancho - 1)
                {
                    suma += mapa[x + 1, y].altura;
                    count++;
                }

                if (y > 0)
                {
                    suma += mapa[x, y - 1].altura;
                    count++;
                }

                if (y < alto - 1)
                {
                    suma += mapa[x, y + 1].altura;
                    count++;
                }

                float promedio = (float)suma / count;

                float original = mapa[x, y].altura;

                float mezclado = Mathf.Lerp(original, promedio, suavizado);

                copia[x, y].altura = Mathf.RoundToInt(mezclado);
            }
        }

        mapa = copia;
    }

    private void AplicarOffsetsAltura()
    {
        tilemap0.transform.localPosition = new Vector3(0, 0 * unidadAltura, 0);
        tilemap1.transform.localPosition = new Vector3(0, 1 * unidadAltura, 0);
        tilemap2.transform.localPosition = new Vector3(0, 2 * unidadAltura, 0);
        tilemap3.transform.localPosition = new Vector3(0, 3 * unidadAltura, 0);
    }
}