最近翻起以前下载的一些老的教学视频,于是决定重新看一遍,且每周所学做个记录,下面就直接开始。
这篇文章就讲讲教程里面的随机2D地图的实现原理,以及代码展示。
首先效果如下:
右边是使用UntiyEditor所编辑的一个生成面板。左边是实际所生成的地图。
下面是实际源码展示
public void CreateTiles(){
var total = tiles.Length;
for (int i = 0; i < total; i++)
{
var tile = new Tile_();
tile.id = i;
tiles[i] = tile;
}
FindNeighbors();
}
private void FindNeighbors()
{
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < columns; c++)
{
var tile = tiles[columns*r+c];
if (r0)
{
tile.AddNeighbor(Sides.Left,tiles[columns*r+c-1]);
}
if (r>0)
{
tile.AddNeighbor(Sides.Top,tiles[columns*(r-1)+c]);
}
}
}
}
首先要想实现2D地图,最简单的就是先能按照自己所设定的尺寸生成一个矩形的地图,且每一个单位是由一张sprite组成,这个应该不难。然后,按照面向对象的思维,每一个sprite身上都有一个tile的脚本,用来记录自身的信息,以及他周围的邻居,以上代码就是简单的生成了tile,然后下面对他上下左右的tile都进行了储存。
接下来就是如何把这个地图包围起来,始现效果如下
首先大家的疑问都是这个地图是如何知道,他的边缘应该是如何进行填充的。这个时候就是用到了一个很简单的知识点,二进制。
private void CalculateAutotileID(){
var sideValues = new StringBuilder();
foreach (Tile_ tile in neighbors)
{
sideValues.Append(tile == null ? "0":"1");
}
autotileID = Convert.ToInt32(sideValues.ToString(),2);
}
在生成完地图的每个Tile以及记录了他们的邻居时候,根据他们邻居有或者没,用0和1来表示。那么就可以遍历出所有的情况,比如这个tile如果他周围都是空的只有他自己,那么他上下左右都是0,换成二进制就是 0,0,0,0,如果他周围都有方块,那么换成二进制就是1,1,1,1。这就是两种极端的情况。以此类推,我们根据每个tile储存的他自己周围的邻居,就可以得到每个tile当前处于什么状态,然后转换为10进制的数字,这就是上文的autotileID,并储存在他们每个tile自身的类身上,然后只要在合适的时机。根据这个ID加载对应的sprite,就能实现一个最简单的四四方方的地图。
接下来我们讲讲,当我们生成了一个矩型的地图之后我们如何让他周围被腐蚀掉,从而实现如下图的效果
public void CreateIsland(
float erodePrecent,
int erodeIterations,
float treePercent,
float hillPercent,
float mountainPercent,
float townsPercent,
float monsterPercent,
float lakePercent
)
{
DecorateTiles(landTiles,lakePercent,TileType.Empty);
for (int i = 0; i < erodeIterations; i++)
{
DecorateTiles(coastTiles,erodePrecent,TileType.Empty);
}
var openTiles = landTiles;
RandomizeTileArray(openTiles);
if (openTiles!= null && openTiles[0] != null)
{
openTiles[0].autotileID = (int)TileType.Castle;
}
DecorateTiles(landTiles,treePercent,TileType.Tree);
DecorateTiles(landTiles,hillPercent,TileType.Hills);
DecorateTiles(landTiles,mountainPercent,TileType.Mountain);
DecorateTiles(landTiles,townsPercent,TileType.Towns);
DecorateTiles(landTiles,monsterPercent,TileType.Monster);
}
public void DecorateTiles(Tile_[] tiles,float percent,TileType type)
{
var total = Mathf.FloorToInt(tiles.Length*percent);
RandomizeTileArray(tiles);
for (int i = 0; i < total; i++)
{
var tile = tiles[i];
if(type == TileType.Empty)
{
tile.ClearNeighbors();
}
tile.autotileID = (int)type;
}
}
上面的代码,创建了一个简单的方法,DecorateTiles,传入指定的tile数组,然后根据百分比,把他们换成制定的tile类型。
腐蚀的方法很简单,就在第一个方法的for循环里面,他是找到了所有autotileID小于15的方块,小于15就代表了他们都是边缘tile,然后对他们随机进行置空,然后根据unityEditor所填下的值。决定执行几次置空循环。
里面的其他代码也很容易理解,就是获取了数值为15的autotileID的方块,数值为15就是都为里面填充的方块,只要根据百分比转换成你需要的树,山,之类的,就能实现上图最简单的效果。
总结一下,这个简单的2D随机地图,就是通过二进制获得了所有地图的关系信息,用这个关系信息进行数据的处理,填充,置空。来实现出如上图的效果。