从零开始入门创作游戏——地砖元素的抽象化和重构+地表树的生成

前面介绍的都是仅将贴图放置在unity场景中,而这些贴图并没有额外的属性,如果需要增加属性,则需要自己创建一个类,后面只需增加该类的属性就能保证所有地砖都能继承。


  • 创建地砖类

我们创建一个新的脚本,但是该脚本继承的不是Unity默认的父类【MonoBehaviour】,而是【ScriptableObject】,这个类能直接通过Unity页面创建新的类来编辑

using System.Collections;
using UnityEngine;

[CreateAssetMenu(fileName = "新砖块", menuName = "砖块类")]
 
public class TileClass : ScriptableObject
//这个类是将所有砖块抽象出基本属性。
{
    public string tileName;    //砖块名字
    public Sprite tileSprite;  //砖块贴图
}

脚本保存后,就能在unity的资产内创建对应的新砖块类

创建了新的类后,能直接设置该类的名字和贴图元素,这样还有一个好处就是不需要额外修改切割sprite元素的名字。

补充:

如果想修改切割sprite的名字,需要进入到材质中编辑

 

选择每一个切割的元素重命名(右下角的name) 

扫描二维码关注公众号,回复: 17237266 查看本文章


  • 创建砖块集的类

由于整个游戏中有很多不同的砖块,如果不想通过脚本来引用类,可以创建一个类来通过unity的GUI来维护。每次新增新的砖块类型能直接在这里添加就可以。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "砖块集", menuName = "砖块集")]
public class TileAtlas : ScriptableObject
 //这个类是用来绑定砖块类所对应的不同种类砖块所使用的素材
{
    public TileClass stone;    //岩石素材

    public List<TileClass> dirtSprites = new List<TileClass>();   //复数的地块素材

    public List<TileClass> grassSprites = new List<TileClass>();  //复数的草地素材

    public List<TileClass> woodSprites = new List<TileClass>();   //复数的木头素材

    public TileClass leftLeaf;    //左侧树叶素材
    public TileClass rightLeaf;   //右侧树叶素材

}

同样右键创建该类,然后通过拖动


  • 重构生成砖块的代码

由于生成了地砖集这个类,可以在沙盒地图生成的代码中将原本引用改成单独引用地图集类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Sandbox_seed : MonoBehaviour
{
    [Header("砖块材质")]    //脚本参数中的标题
    public TileAtlas tileAtlas;   //创建该类就能直接调用子类中的各种砖块
}

接下来重构生成地砖的函数,将原本的 sprite 改成 tileClass ,原本的 stone 等 public元素改成类似tileAtlas.stone,部分子类中不是单纯的一个类,而是复数的类列表,所以也需要重构GetSprite函数成GetTileClass函数

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

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

                //判断该生成的是什么地貌
                if (y < surfaceNoise - dirtNoise) tileClass = tileAtlas.stone;                

                else if (y <= surfaceNoise - 1) tileClass = GetTileClass(tileAtlas.dirts); 

                else tileClass = GetTileClass(tileAtlas.grasses);                            

                if (noiseTexture.GetPixel(x, y).r > caveFreq)
                {
                    PlaceTile(tileClass, x, y);
                }

            }
        }
    }

GetSprite重构成GetTileClass函数,原理和原本的函数一样,改变的是返回的是tileClass类

    public TileClass GetTileClass(List<TileClass> TileSet)
    {
        int randomIndex = Random.Range(0, TileSet.Count);
        TileClass tileClass = TileSet[randomIndex];
        return tileClass;
    }

创建一个类List<Vector2> worldTileVectorList ,用于记录整个世界生成的砖块所在的(x,y)坐标。只有该位置没有砖块才能生成砖块(而如果类似泰拉瑞亚那种还有墙的话,需要增加墙面的列表来记录墙面)

    public List<Vector2> worldTileVectorList = new List<Vector2>();


    public void PlaceTile(TileClass tileSprite, int x, int y)
    {
        if (!worldTileVectorList.Contains(new Vector2(x, y)))   //判断该地址是否已经存在了砖块,如果存在则不生成
        {
            GameObject newTile = new GameObject();
            newTile.transform.parent = this.transform;
            newTile.AddComponent<SpriteRenderer>();
            newTile.GetComponent<SpriteRenderer>().sprite = tileSprite.tileSprite;      //生成的元素为上面条件判断后的砖块
            newTile.name = tileSprite.tileName;
            newTile.transform.position = new Vector2(x, y);
            worldTileVectorList.Add(newTile.transform.position);//将该地址记录下来
        }
    }

根据这个新增的判断我们可以增加地表生成树的代码


  • 草地地砖上生成树

    public float treeChance;  //生成树的概率,1为每格都生成,0为不生成


    public void GenerateTexture()
    {

                /* 前面代码不变 */
                if (noiseTexture.GetPixel(x, y).r > caveFreq)
                //GetPixel(x, y).r 是指该像素位置的RGB值中的R值,使用b和g都可以
                //如果该像素所在位置的颜色比洞窟参数的颜色深(白)的话,就生成该砖块,否则留空为洞穴
                {
                    PlaceTile(tileClass, 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);
                    }
                }
            }
        }
    }

生成树的代码如下,如果想要树的形状更多种,则添加各种随机判断生成树叶和木头的数量

    public void PlaceTree(int x, int y)
    {
        int woodSpritesNum = Random.Range(0, 2);   //树的材质,2选1
        int treeHeight = Random.Range(6, 12);      //树的随机高度
        for (int i = 0; i < treeHeight; i++)       
        {
            PlaceTile(tileAtlas.woods[woodSpritesNum], x, y + i + 1);    //生成树砖块的坐标,为草地往上一格即y+1
            if (i >= 4)      //当大于4时开始生成树叶
            {
                for (int i2 = 1; i2 <= 2; i2++)
                {
                    PlaceTile(tileAtlas.leftLeaf, x - i2, y + i + 1);    //生成树砖块的坐标,为树往左右1格和2格
                    PlaceTile(tileAtlas.rightLeaf, x + i2, y + i + 1);
                }
            }
        }
    }

最终效果如下,可以看到在生成树的概率为1时,没有生成草地砖块的位置不生成树

如果想树生成得比较自然的,概率为0.2就可以了

猜你喜欢

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