You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何基于CircularNoise脚本生成可控分层的类泰拉瑞亚圆形行星?

嘿,看起来你已经搞定了噪声生成的基础框架,接下来要实现类似Terraria的圆形行星Tile生成+分层控制其实没那么复杂,咱们一步步来拆解:

核心思路:用「距离+噪声扰动」实现分层圆形地形

圆形行星的本质是基于Tile到行星中心的距离划分层级,再用你的CircularNoise给每层边缘添加随机扰动,避免完美圆形的呆板感。

第一步:先定义行星的分层规则

首先得明确你想要的各层(比如核心熔岩、深层岩石、表层土壤、地表草地),给每层设定关键参数:

// 先搞个枚举定义Tile类型(根据你的游戏需求扩展)
public enum TileType { Empty, Lava, Stone, Dirt, Grass }

// 定义行星层的结构,控制每层的深度和特性
public class PlanetLayer
{
    public int MinRadius { get; set; } // 层的内半径(深度下限)
    public int MaxRadius { get; set; } // 层的外半径(深度上限)
    public TileType TileType { get; set; } // 该层对应的Tile类型
    public float NoiseStrength { get; set; } // 噪声对层边缘的扰动幅度(值越大地形越崎岖)
}

比如你可以这样配置分层:

var planetLayers = new List<PlanetLayer>
{
    new PlanetLayer { MinRadius = 0, MaxRadius = 20, TileType = TileType.Lava, NoiseStrength = 2f },
    new PlanetLayer { MinRadius = 20, MaxRadius = 60, TileType = TileType.Stone, NoiseStrength = 5f },
    new PlanetLayer { MinRadius = 60, MaxRadius = 80, TileType = TileType.Dirt, NoiseStrength = 8f },
    new PlanetLayer { MinRadius = 78, MaxRadius = 85, TileType = TileType.Grass, NoiseStrength = 10f }
};

第二步:完善你的CircularNoise脚本

你的代码没贴全,我给你补个能输出可用噪声值的方法(用Unity的Perlin Noise举例,其他引擎可以替换成对应噪声函数):

public class CircularNoise 
{
    System.Random random = new System.Random(); 
    float offsetX, offsetY; 
    float scale; 

    public CircularNoise(float scale) 
    { 
        offsetX = random.Next(100000); 
        offsetY = random.Next(100000); // 补全随机偏移量
        this.scale = scale;
    }

    // 生成0-1之间的噪声值,用于扰动地形边缘
    public float GetNoise(float x, float y)
    {
        // 偏移量避免重复地形,scale控制噪声的细腻程度(值越小噪声越细碎)
        return Mathf.PerlinNoise(x + offsetX, y + offsetY);
    }
}

第三步:核心Tile生成逻辑

遍历每个Tile,计算它到行星中心的距离,加上噪声扰动后判断属于哪一层,然后设置对应Tile:

// 假设你的地图尺寸是mapWidth x mapHeight,行星中心在(centerX, centerY)
public void GeneratePlanet(int centerX, int centerY, int mapWidth, int mapHeight, List<PlanetLayer> layers)
{
    CircularNoise noiseGenerator = new CircularNoise(20f); // 调整scale控制噪声细腻度

    for (int x = 0; x < mapWidth; x++)
    {
        for (int y = 0; y < mapHeight; y++)
        {
            // 1. 计算Tile到行星中心的基础直线距离
            float baseDistance = Mathf.Sqrt(Mathf.Pow(x - centerX, 2) + Mathf.Pow(y - centerY, 2));
            TileType currentTile = TileType.Empty; // 默认是太空空Tile

            // 2. 遍历所有层,找到当前Tile所属的层
            foreach (var layer in layers)
            {
                // 把Tile坐标归一化到噪声的缩放范围内
                float noiseX = (x - centerX) / noiseGenerator.scale + noiseGenerator.offsetX;
                float noiseY = (y - centerY) / noiseGenerator.scale + noiseGenerator.offsetY;
                float noiseValue = noiseGenerator.GetNoise(noiseX, noiseY);

                // 用噪声扰动距离:(noiseValue-0.5f)让噪声在-0.5到0.5之间波动,避免只向外凸
                float perturbedDistance = baseDistance + (noiseValue - 0.5f) * layer.NoiseStrength;

                // 判断是否在当前层的半径范围内
                if (perturbedDistance >= layer.MinRadius && perturbedDistance <= layer.MaxRadius)
                {
                    currentTile = layer.TileType;
                    break; // 找到对应层就停止检查,内层优先级高于外层
                }
            }

            // 3. 设置当前Tile(替换成你游戏里设置Tile的方法)
            SetTileAtPosition(x, y, currentTile);
        }
    }
}

几个实用优化点

  • 分层顺序:把内层(比如熔岩核心)放在layers列表的最前面,这样遍历的时候会优先匹配内层,避免外层Tile覆盖内层。
  • 平滑过渡:如果想让层与层之间的边界更自然,可以在距离接近层边缘时,混合两种Tile的类型(比如用噪声值做权重)。
  • 性能优化:如果地图很大,建议用多线程异步生成Tile,或者提前预计算每层的大致范围,减少不必要的噪声计算。

内容的提问来源于stack exchange,提问作者Liam Earle

火山引擎 最新活动