我可以帮你翻译这段文本。
我正在开发一个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);
}
}
评论 (0)