游戏中的随机地形生成算法(三)

在上篇教程中,我们已经把Map中的每个点都实实在在的画了出来,四个点形成一个正方形。其中,正方形的每条边都有一个中点。


那么,这节课我们来把该连在一起的点连起来,绘制我们的mesh。


    public class Square
    {
        public ControlNode topLeft, topRight, bottomLeft, bottomRight;      //一个矩形拥有四个控制节点  
        public Node centerTop, centerLeft, centerRight, centerBottom;       //还有四个节点
        
        public int configuration;

        public Square(ControlNode _topLeft, ControlNode _topRight, ControlNode _bottomLeft, ControlNode _bottomRight)   //我们只需要定义四个控制节点
        {   
            topLeft = _topLeft;        
            topRight = _topRight;
            bottomLeft = _bottomLeft;
            bottomRight = _bottomRight;

            //控制节点包含节点
            centerTop = topLeft.right;
            centerBottom = bottomLeft.right;
            centerLeft = bottomLeft.above;
            centerRight = bottomRight.above;

            if (topLeft.isActive)
                configuration += 8;
            if (topRight.isActive)
                configuration += 4;
            if (bottomRight.isActive)
                configuration += 2;
            if (bottomLeft.isActive)
                configuration += 1;
        }
    }

首先完善一下我们的Square类,增加了一个int变量configuration,我们用它来记录当前矩形控制节点的激活情况,

如果左上激活:对应1000=8,

如果右上激活:对应0100=4;

如果左下激活:对应0010=2;

如果右下激活:对应0001=1;


然后我们定义一个分形函数TriangulateSquare,顾名思义,用来把一个Square分割成三角形。


void TriangulateSquare(Square square)
    {
        switch (square.configuration)
        {
            //1 point
            case 1:
                MeshFromPoints(square.centerBottom, square.bottomLeft, square.centerLeft);
                break;
            case 2:
                MeshFromPoints(square.centerRight, square.bottomRight, square.centerBottom);
                break;
            case 4:
                MeshFromPoints(square.centerTop, square.topRight, square.centerRight);
                break;
            case 8:
                MeshFromPoints(square.topLeft, square.centerTop, square.centerLeft);
                break;

            //2 points
            case 3:
                MeshFromPoints(square.centerRight, square.bottomRight, square.bottomLeft, square.centerLeft);
                break;
            case 6:
                MeshFromPoints(square.centerTop, square.topRight, square.bottomRight, square.centerBottom);
                break;
            case 9:
                MeshFromPoints(square.topLeft, square.centerTop, square.centerBottom, square.bottomLeft);
                break;
            case 12:
                MeshFromPoints(square.topLeft, square.topRight, square.centerRight, square.centerLeft);
                break;
            case 5:
                MeshFromPoints(square.centerTop, square.topRight, square.centerRight, square.centerBottom, square.bottomLeft, square.centerLeft);
                break;
            case 10:
                MeshFromPoints(square.topLeft, square.centerTop, square.centerRight, square.bottomRight, square.centerBottom, square.centerLeft);
                break;

            // 3 point:
            case 7:
                MeshFromPoints(square.centerTop, square.topRight, square.bottomRight, square.bottomLeft, square.centerLeft);
                break;
            case 11:
                MeshFromPoints(square.topLeft, square.centerTop, square.centerRight, square.bottomRight, square.bottomLeft);
                break;
            case 13:
                MeshFromPoints(square.topLeft, square.topRight, square.centerRight, square.centerBottom, square.bottomLeft);
                break;
            case 14:
                MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.centerBottom, square.centerLeft);
                break;

            // 4 point:
            case 15:
                MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.bottomLeft);
                break;
        }
        
    }


在这里,我们使用到了刚刚定义的configuration来分辨16种情形,在每种情形中,我们又使用了MeshFromPoints这个方法来构建mesh。


    void MeshFromPoints(params Node[] nodes)
    {
        AssignVerticals(nodes);	//在创建三角形之前,先存储一下它的顶点信息

        if (nodes.Length>=3)
        {
            CreateTriangle(nodes[0], nodes[1], nodes[2]);
        }
        if (nodes.Length >= 4)
        {
            CreateTriangle(nodes[0], nodes[2], nodes[3]);
        }
        if (nodes.Length >= 5)
        {
            CreateTriangle(nodes[0], nodes[3], nodes[4]);
        }
        if (nodes.Length >= 6)	//如果有6个点,那我们需要创建4个三角形
        {
            CreateTriangle(nodes[0], nodes[4], nodes[5]);
        }
    }

    void AssignVerticals(Node[] points)
    {
        for (int i = 0; i < points.Length;i++ )
        {
            if (points[i].vertexIndex==-1)
            {
                points[i].vertexIndex = verticals.Count;
                verticals.Add(points[i].position);
            }
        }
    }

    void CreateTriangle(Node a, Node b, Node c)
    {
        triangles.Add(a.vertexIndex);
        triangles.Add(b.vertexIndex);
        triangles.Add(c.vertexIndex);
    }

你也许已经注意到了,我们还没有定义verticals和triangles,把它们定义为类的字段:


List<Vector3> verticals;
    List<int> triangles;


就快完成了!现在给我们的游戏物体挂上Mesh Filter和Mesh Renderer组件,同时创建一个黑色的Material材质球,挂载到Mesh Renderer组件里的Materail数组中。


接着我们把MeshGenerator中的OnGizmosDraw函数注释掉,已经不需要它啦~

同时修改以下代码:


public void GenerateMesh(int[,] map, int squareSize)
    {
        squareGrid = new SquareGrid(map, squareSize);

        verticals=new List<Vector3>();
        triangles=new List<int>();

        for (int x = 0; x < squareGrid.squares.GetLength(0); x++)
        {
            for (int y = 0; y < squareGrid.squares.GetLength(1); y++)
            {
                TriangulateSquare(squareGrid.squares[x, y]);
            }
        }

        Mesh mesh=new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;

        mesh.vertices=verticals.ToArray();
        mesh.triangles=triangles.ToArray();
        mesh.RecalculateNormals();
    }

我们使用代码手动定义了一个mesh组件。好,到现在已经完成了,我们来运行看下,希望不会出错:




喔噢!大功告成,简直不能再棒了!


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值