初学者关于Unity的tilemap随机生成[1]
这个系列用于记载一个初学者自学Unity的时候写出的一些脑瘫代码首先了解一下Unity的TileMap
想要在脚本中引用TileMap对象,我们首先需要using UnityEngine.Tilemaps,像这样
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
然后我们要想随机化生成一个TileMap,必然要有一个函数向TileMap中添加Tile对象,那么我们便找到了SetTile()方法
可以看到,SetTile方法有两个参数 position 和 tile,其中position代表了物块在TileMap中的位置,tile则代表了物块的类型。、
那么思路很清晰了,首先随机化出一个二维数组,然后解析二维数组并向空TileMap中添加物块。
1.随机化二维数组
我们要做的是一个2D的横板像素游戏,因此我选择先生成地面,首先定义一个int类型的量,表示当前的地面坐标高度,然后定义两个量worldHeight和worldWidth,既世界的高和宽
int groundHeight = 10;
public int worldHeight = 100;
public int worldWidth = 100;
然后定义一个二维数组tileType和一个一维数组groundPos
int[,] tileType;
int[] groundPos
为什么要是10呢,因为我不可能让世界的生成从第0格开始。然后我使用rand随机数来不断改变这个值,并给二维数组赋值,同时在groundPos中记录下每列的地面高度(原因之后再说)
for(int i = 0; i < worldWidth; i++)
{
groundHeight = Mathf.Max(groundHeight + Random.Range(-3, 3), 5);
groundPos = groundHeight + 1;
tileType = 1;
for(int j = 0; j < groundHeight; j++)
{
tileType = 2;
}
}
可以看到,我用了一个Mathf.Max()函数来确定groundHeight的大小,为什么呢,因为游戏中地面不可能只有一层,那么我们就要让地面位于至少5高度的位置,这样地层厚度至少为4,就不会显得单薄。然后我又套了一个for循环,让所有的地面之下全都为纯色的土壤。
下一步我称之为美化地图,因为我们会发现,地面总是会出现这种情况:一块平整的地面上突然出现一个小坑,且只有一块,显得非常奇怪;也有可能是突出一块,同样很奇怪,而且不美观,那么我们就要想办法解决这个问题。
怎么办呢,首先我们可以访问这个二维数组,那么就代表着我们遍历一遍二维数组,寻找所有的两边是物块且中间没有物块的,或者是两边没有物块,中间有物块的情况,把中间的地面高度改为和两边相同,便可以达到平整地面的效果
for(int i = 1; i < worldWidth - 1; i++)
{
if(tileType - 1] == 1 && tileType - 1] == 1 && tileType - 1] == 0)
{
tileType - 1] = 1;
groundPos = groundPos;
}
}
for(int i = 1; i < worldWidth - 1; i++)
{
if(tileType - 1] == 0 && tileType - 1] == 0 && tileType - 1] == 1)
{
for(int j = groundPos; j < groundPos; j++)
{
tileType = 0;
}
tileType - 1] = 1;
groundPos = groundPos;
}
}
然后我们把地面高度之下的所有物块设定为土壤
for(int i = 0; i < worldWidth; i++)
{
for(int j = 0; j < groundPos - 1; j++)
{
tileType = 2;
}
}
最后一步,长草,这也是我之前存下地面位置的原因,虽然草和地面是两个TileMap里面的,但是我们可以用一个二维数组来存储,最后设定Tile时把草设置在第二个TileMap里面即可。
当然也不能每块地都长草,所以我们加上rand
for(int i = 0; i < worldWidth; i++)
{
if(Random.Range(0, 5) == 1) tileType] = 3;
}
至此,用于存放物块信息的二维数组就设定好了
2.设定TileMap
首先我们引用两个TileMap,一个叫做tiles,另一个叫做otherThings
public Tilemap tiles;
public Tilemap otherThings;
然后再引用三种TileBase
public TileBase dirt_up, dirt_in;
public TileBase grass;
然后我们就可以开始快乐地生成我们的TileMap了!
生成方法也很简单,遍历我们之前设定好的二维数组,把每个数字对应设定为TileMap里面的Tile即可,注意TileMap中Tile的位置是一个Vector3,既空间坐标,但是由于我们做的是2D游戏,z轴设定为0即可。
void initData()
{
for(int i = 0; i < worldWidth; i++)
{
for(int j = 0; j < worldHeight; j++)
{
switch(tileType)
{
case 1 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_up); break;}
case 2 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_in); break;}
case 3 : {otherThings.SetTile(new Vector3Int(i, j, 0), grass); break;}
}
}
}
}
这里我用的是switch,因为日后可能会有更多的物块加入到地图里面,全都用if的话需要全部判断一遍,耗时耗力。
最后注意别忘了在Start()方法中执行之前的方法。
至此一个简单的TileMap生成就做好了。最后我们放一下所有的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class WorldSpwaner : MonoBehaviour
{
public Tilemap tiles;
public Tilemap otherThings;
public TileBase dirt_up, dirt_in;
public TileBase grass;
int[,] tileType;
int[] groundPos;
string[] otherThingsType;
public int worldHeight = 100, worldWidth = 100;
void Start()
{
initMapTilesInfo();
initData();
}
public enum TileNum
{
none,
Dirt_up,
Dirt_in,
Grass,
Dirt_left,
Dirt_right,
Dirt_left_up,
dirt_right_up
}
/// <summary>
/// 根据编号确定Tile的类型
/// </summary>
void initData()
{
for(int i = 0; i < worldWidth; i++)
{
for(int j = 0; j < worldHeight; j++)
{
switch(tileType)
{
case 1 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_up); break;}
case 2 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_in); break;}
case 3 : {otherThings.SetTile(new Vector3Int(i, j, 0), grass); break;}
case 8 : {break;}
case 4 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_right); break;}
case 5 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_right_up); break;}
case 6 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_left); break;}
case 7 : {tiles.SetTile(new Vector3Int(i, j, 0), dirt_left_up); break;}
}
}
}
}
/// <summary>
/// 初始化地图Tile的编号
/// </summary>
void initMapTilesInfo()
{
tileType = new int;
groundPos = new int;
for(int i = 0; i < worldWidth; i++)
{
groundPos = 0;
for(int j = 0; j < worldHeight; j++)
{
tileType = 0;
}
}
int groundHeight = 10;
//初步生成地图
for(int i = 0; i < worldWidth; i++)
{
groundHeight = Mathf.Max(groundHeight + Random.Range(-3, 3), 5);
groundPos = groundHeight + 1;
tileType = 1;
for(int j = 0; j < groundHeight; j++)
{
tileType = 2;
}
}
//美化生成的地图
for(int i = 1; i < worldWidth - 1; i++)
{
if(tileType - 1] == 1 && tileType - 1] == 1 && tileType - 1] == 0)
{
tileType - 1] = 1;
groundPos = groundPos;
}
}
for(int i = 1; i < worldWidth - 1; i++)
{
if(tileType - 1] == 0 && tileType - 1] == 0 && tileType - 1] == 1)
{
for(int j = groundPos; j < groundPos; j++)
{
tileType = 0;
}
tileType - 1] = 1;
groundPos = groundPos;
}
}
for(int i = 0; i < worldWidth; i++)
{
for(int j = 0; j < groundPos - 1; j++)
{
tileType = 2;
}
}
//长草
for(int i = 0; i < worldWidth; i++)
{
if(Random.Range(0, 5) == 1) tileType] = 3;
}
}
} 这个代码有点问题,不完整,注释相关代码后正常 ,使用方式为在grid游戏对象上绑定这个代码 并把2个tileMap对象拖入代码变量上,再把地图图片资源绑定到tileBase变量上点击运行才可正常生成
页:
[1]