游戏中的随机地形生成算法(二)
发表于2018-05-07
继续介绍随机地形生成算法系列,在上篇教程中,我们已经可以生成一个还看得过去的随机地形了。下面我们用gizmos画出了密密麻麻的正方体来展示整个地图。







现在想象一下,我们把每个正方体缩小为一个点,就会出现下面的情况:
每个点有两种状态:0和1,分别代表道路和障碍,我们把这四个点当成一个二进制数字0000。
当它们全部是1的时候,也就是1111=15。如图:
那我们可以得到的信息就是这四个点的组合方式有16种。每一种组合对应一种网格(mesh),而网格是由三角形组成的,下面是几个示例:
可以观察到的是,除了四个顶点,边的中点也用来组成网格。我们在这里定义顶点为控制节点,边的中点为节点。每个控制节点拥有两个节点:上方节点和右方节点。
下面我们来定义它们的数据结构,新建一个脚本命名为MeshGenerator:
public class Node { public Vector3 position; public int vertexIndex = -1;<span style="white-space:pre;"> </span>//顶点索引,我们以后将会用到 public Node(Vector3 _pos)<span style="white-space:pre;"> </span>//节点的构造函数,需要传入它的位置 { position = _pos; } }
public class ControlNode : Node { public bool isActive; //控制节点是否激活 public Node above, right; //每个控制节点拥有两个节点 public ControlNode(bool _isActive, Vector3 _pos, int squareSize) : base(_pos) //从父类构造函数传入位置,squareSize为四个控制节点形成的矩形的边长 { isActive = _isActive; above = new Node(position + Vector3.forward * squareSize / 2f); right = new Node(position + Vector3.right * squareSize / 2f); } }
public class Square { public ControlNode topLeft, topRight, bottomLeft, bottomRight; //一个矩形拥有四个控制节点 public Node centerTop, centerLeft, centerRight, centerBottom; //还有四个节点 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; } }
public class SquareGrid { public Square[,] squares; //代表了整张网格的信息 public SquareGrid(int[,] map, int squareSize) //构造函数传入Map数组信息和单个矩形的边长 { int nodeCountX = map.GetLength(0); //X方向上节点的数量 int nodeCountY = map.GetLength(1); //Y方向上节点的数量 float mapWidth = nodeCountX * squareSize; //地图的宽 float mapHeight = nodeCountY * squareSize; //地图的高 ControlNode[,] controlNodes=new ControlNode[nodeCountX,nodeCountY]; //用来存储整张地图上的控制节点 for (int x = 0; x < nodeCountX;x++ ) { for (int y = 0; y < nodeCountY; y++) { Vector3 pos=new Vector3(-mapWidth/2f+x*squareSize+squareSize/2,0,-mapHeight/2f+y*squareSize+squareSize/2); controlNodes[x,y]=new ControlNode(map[x,y]==1,pos,squareSize); } } squares=new Square[nodeCountX-1,nodeCountY-1]; //矩形的数量总是比节点的数量少1 for (int x = 0; x < nodeCountX-1;x++ ) { for (int y = 0; y < nodeCountY-1; y++) { squares[x,y]=new Square(controlNodes[x,y+1],controlNodes[x+1,y+1],controlNodes[x,y],controlNodes[x+1,y]); } } } }
很好,我们现在基本完成了这节内容,我们已经得到了使用SquareGrid存储的地图信息。
现在要做的是给MeshGenerator类添加一个字段和一个方法:
public SquareGrid squareGrid; public void GenerateMesh(int[,] map, int squareSize) { squareGrid = new SquareGrid(map, squareSize); }
接着我们需要在MapGenerator里调用这个方法,对GenerateMap函数作出如下改动:
void GenerateMap() { map=new int[width,height]; RandomFillMap(); //随机生成地图 for (int i = 0; i < 4; i++) { SmoothMap(); } MeshGenerator meshGen = GetComponent<MeshGenerator>(); meshGen.GenerateMesh(map, 1); }
嗯,你应该注意到了,我们应该把这两个脚本挂在同一物体上,否则是无法直接GetComponent的。
先别急着从这个关闭代码界面,我们还要把OnDrawGizmos函数注释掉,然后在MeshGenerator中重新定义一个OnDrawGizmos方法:
oid OnDrawGizmos() { if (squareGrid != null) { for (int x = 0; x < squareGrid.squares.GetLength(0); x ++) { for (int y = 0; y < squareGrid.squares.GetLength(1); y ++) { Gizmos.color = (squareGrid.squares[x,y].topLeft.active)?Color.black:Color.white; Gizmos.DrawCube(squareGrid.squares[x,y].topLeft.position, Vector3.one * .4f); Gizmos.color = (squareGrid.squares[x,y].topRight.active)?Color.black:Color.white; Gizmos.DrawCube(squareGrid.squares[x,y].topRight.position, Vector3.one * .4f); Gizmos.color = (squareGrid.squares[x,y].bottomRight.active)?Color.black:Color.white; Gizmos.DrawCube(squareGrid.squares[x,y].bottomRight.position, Vector3.one * .4f); Gizmos.color = (squareGrid.squares[x,y].bottomLeft.active)?Color.black:Color.white; Gizmos.DrawCube(squareGrid.squares[x,y].bottomLeft.position, Vector3.one * .4f); Gizmos.color = Color.grey; Gizmos.DrawCube(squareGrid.squares[x,y].centreTop.position, Vector3.one * .15f); Gizmos.DrawCube(squareGrid.squares[x,y].centreRight.position, Vector3.one * .15f); Gizmos.DrawCube(squareGrid.squares[x,y].centreBottom.position, Vector3.one * .15f); Gizmos.DrawCube(squareGrid.squares[x,y].centreLeft.position, Vector3.one * .15f); } } } }
同样的,这里我们首先判断每个点是否激活,然后确定它们的颜色,再画出它们。
我们来看看效果吧:
看不太清楚,放大看一下:
NICE!正是我们想要的效果~!
来自:https://blog.csdn.net/qq_17758883/article/details/78181769
如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引