从零开始入门创作游戏——矿物的随机生成

由于矿物生成的原理与地图生成的原理一样,都是根据随机噪音图像来生成对应的砖块,所以需要将生成噪音图的函数进行重构,之后每个矿物都生成唯一的贴图来参考生成位置。


  • 重构噪音函数

其中增加了3个参数,用来保证每个砖块都能生成自己唯一的图像。由于我的seed取值范围为

seed = Random.Range(10000, 20000)

所以在 Mathf.PerlinNoise 的参数中除以了1000,为的是增加 frequent 的取值范围,在Unity页面中调试时可以更加方面修改参数,并让效果图更明显

此外还修改了生成的像素颜色,优化成仅有黑白两色的图像,能更清楚的看到效果

    public void GenerateNoiseTexture(float frequent, float limit ,Texture2D noiseTexture)
    //frequent 噪音频率,越小噪音越不明显,越大越明显
    //limit    临界值,大于临界值则为白,小于临界值为黑
    //noiseTexture    最终生成的噪音图像
    {
        for (int x = 0; x < noiseTexture.width; x++)
        {
            for (int y = 0; y < noiseTexture.height; y++)
            {
                float v = Mathf.PerlinNoise((x + seed)* frequent/1000, (y + seed ) * frequent/1000);
                if (v > limit)
                    noiseTexture.SetPixel(x, y, Color.white);
                else noiseTexture.SetPixel(x, y, Color.black);
                //SetPixel函数根据像素位置,只有当噪音值大于阈值才会生成对应x,y坐标下的像素颜色为白色像素,否则生成黑色像素
            }
        }
        noiseTexture.Apply();  //将上面点生成对应的二位噪音图保存
    }

  • 生成矿物和地图的噪音图

增加了以下参数,对应的作用也注释上了

public class Sandbox_seed : MonoBehaviour
{
    [Header("世界参数")]
    public Texture2D mapNoiseTexture;  //地图噪音材质图
    public float caveFreq = 50;        //山洞参数,数值越大洞越多
    public float caveSize = 0.25f;

    [Header("矿物参数")]
    public Texture2D copperNoiseTexture;  //铜矿噪音材质图
    public Texture2D goldNoiseTexture;    //金矿噪音材质图

    public int copperFreq = 100;          //铜矿噪音参数
    public int goldFreq = 200;            //金矿噪音参数

    public float copperSize = 0.3f;       //铜矿生成概率
    public float goldSize = 0.25f;        //金矿生成概率
}

 为了方便调试参数,增加了以下系统自带的函数OnValidate(),这个函数的作用是在Unity页面中对参数进行修改时,立刻更新对应的对象。在这个代码中,就是为了能更方便调试噪音参数。注意矿物材质的第二个参数和世界地图材质不一样。

public class Sandbox_seed : MonoBehaviour
{
    public void OnValidate()
    {
        if (mapNoiseTexture == null)
        //如果一开始的mapNoiseTexture为空,则重新生成一个。
        //因为原本mapNoiseTexture是只有在开始运行才会生成的,如果不加这句话就会报错
        {
            mapNoiseTexture = new Texture2D(worldwidth, worldheight);
            copperNoiseTexture = new Texture2D(worldwidth, worldheight);
            goldNoiseTexture = new Texture2D(worldwidth, worldheight);
        }
        GenerateNoiseTexture(caveFreq, caveSize, mapNoiseTexture);
        //注意这里的是 1 减去矿物尺寸,临界值为1时全部为白即全图生成对应矿物,而0为黑即不生成矿物
        //这点是和地图的洞穴参数相反。
        GenerateNoiseTexture(copperFreq, 1f - copperSize, copperNoiseTexture);
        GenerateNoiseTexture(goldFreq, 1f - goldSize, goldNoiseTexture);
    }
}

这个是世界地图的噪音材质图,白色为地砖位置

这个是矿物的噪音材质图,白色的为矿物位置


  • 添加矿物地砖类

和之前的石头、草地、泥土一样,在Unity中手动创建地砖类,并添加上名字和贴图

然后在地砖集的类中添加这两个砖块

 同时在生成的地砖集的类里拖拽地砖类

 这样就能在生成地图的时候创建对应的砖块了。


  • 生成地图

 由于添加了矿物,需要调整生成砖块的顺序和逻辑。

注意的是,由于我们生成砖块的判断逻辑是

1. 这个位置是小于地表高度的 【y < surfaceNoise】

2. 这个位置在世界噪音材质中为白色【mapNoiseTexture.GetPixel(x, y).r == 1】

满足这两个条件才能生成砖块。【PlaceTile(tileClass, x, y);】

根据判断的顺序,我这边的矿物是会在地表生成,且优先生成铜矿。而且铜矿上不会长树。

    public void GenerateTexture()
    {
         /* 前面代码不动 */

                TileClass tileClass;       //创建局部变量用来进行判断该地砖应该是什么类型

                //判断该生成的是什么地貌
                if(y < surfaceNoise && mapNoiseTexture.GetPixel(x, y).r == 1)
                { 
                    if (copperNoiseTexture.GetPixel(x,y).r == 1)     //判断在铜矿材质中这个位置是否为白色,是白色就生成铜矿,不是则进行下面的判断
                    {
                        tileClass = tileAtlas.copper;
                    }
                    else if (goldNoiseTexture.GetPixel(x, y).r == 1) //判断在铜矿材质中这个位置是否为白色,是白色就生成金矿,不是则进行下面的判断
                    {
                        tileClass = tileAtlas.gold;
                    }
                    else if (y < surfaceNoise - dirtNoise) tileClass = tileAtlas.stone;          //地表高度减去泥土厚度的为岩石

                    else if (y <= surfaceNoise - 1) tileClass = GetTileClass(tileAtlas.dirts);   //距离地表1且不是岩石的为泥土
                    
                    else tileClass = GetTileClass(tileAtlas.grasses);                            //剩下的,即地表高度等于1的为草地

                    PlaceTile(tileClass, x, y);       //在(x,y)坐标生成砖块

                    if (tileClass.tileName.Contains("Grass") && worldTileVectorList.Contains(new Vector2(x, y)))    //如果这个砖块是草地砖块且生成成功,则进行判断是否生成树
                    {
                        float treeRandom = Random.Range(0f, 1f);
                        if (treeChance >= treeRandom)            //当参数大于随机值,则生成树
                        {
                            PlaceTree(x, y);
                        }
                    }
                }
            }
        }
    }

补充一点:

Color.white 的RGBA值如下,鼠标移动到该参数时也会自己展示

Color.black的RGBA值如下


  • 最终效果 

 在Start() 函数中添加上生成材质的函数和生成地图砖块的函数

    void Start()
    {
        seed = Random.Range(10000, 20000);

        //先声明噪音图的材质类
        mapNoiseTexture = new Texture2D(worldwidth, worldheight);
        copperNoiseTexture = new Texture2D(worldwidth, worldheight);
        goldNoiseTexture = new Texture2D(worldwidth, worldheight);

        //再生成材质
        GenerateNoiseTexture(caveFreq, caveSize, mapNoiseTexture);
        GenerateNoiseTexture(copperFreq, 1f - copperSize, copperNoiseTexture);
        GenerateNoiseTexture(goldFreq, 1f- goldSize, goldNoiseTexture);

        GenerateTexture();
    }

最终生成地图效果如下。生成的矿物数量(copperSize / goldSize)可以自己调整。

猜你喜欢

转载自blog.csdn.net/dwe147/article/details/130646608
今日推荐