这边博客是我自己学习过程中写的第一篇文章,一方面是想与大家分享好的知识,另一方面是为了监督自己不断的学习,希望能给大家带来好的内容分享。
这篇文章的内容是搬运自Youtube上的Sebastian大佬的视频,这个Up主有很多的Unity、Shader、数学、算法等的视频教学,内容都很不错而且讲解非常的清楚,英语不错的小伙伴可以去Youtube上去学习,视频第一课的链接https://www.youtube.com/watch?v=v7yyZZjF1z4&list=PLFt_AvWsXl0eZgMK_DT5_biRkWXftAOf9。不太想看英文教程的下面我用文字的方式来分享。
首先定义出所需要的变量
public int width; //地图的宽度
public int height; //地图的高度
public string seed; //随机种子
public bool useRandomSeed; //是否使用随机中的Flag
[Range(0, 100)]
public int randomFillPercent; //填充百分比
int[,] map; //地图的信息
变量的意义我也都写在上面了。
首先我们要做的就是生成随机的单个Cube通过不同颜色来表现的地图效果。然后我们定义一个GenerateMap的函数用来生成地图信息。初始化二维数组map。第一步生成纯随机无规律的地图信息,通过系统的Random函数来为map数组生成随机的0或者1这里1代表Wall(墙)。设置好宽度高度和填充百分比,此时生成的地图信息是随机,无规律的,如果1用黑色的块,0用白色的块来生成出来地图将会是这样的。
我这里width=128,height=72,RandomFillPercent = 45
这样的地图当然是没法用的,所以我们要给地图信息上规则,平滑地图信息。编写一个SmoothMap函数。平滑地图的原理是这样的,两层循环遍历二维数组map,然后判断一个地图信息点的周围的墙的数量,然后设定一个阈值,墙的数量大于这个阈值就将这个位置的地图信息设置为1(墙),如果小于这个阈值,那么就将地图设置为0(空),然后循环多次下来地图的效果就慢慢呈现出来了,视频作者循环的次数是5次,然后阈值是4,实现出来的效果如下图所示。
现在生成的地图是不是就有点像模像样了呢。
最后再讲一个如果生成显示在Scene视图中,直接贴代码,比较简单很好理解
/// <summary>
/// 绘制
/// </summary>
private void OnDrawGizmos()
{
if (map != null)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Gizmos.color = (map[x, y] == 1) ? Color.black : Color.white;
Vector3 pos = new Vector3(-width / 2 + x + .5f, 0, -height / 2 + y + .5f);
Gizmos.DrawCube(pos, Vector3.one);
}
}
}
}
运行,然后调节Scene视图的视角是从上往下,然后设置成正交视角就能看到效果啦,视频作者还编写了一个鼠标点击就更换地图的随机生成,当然想随机生成还需要设置系统的随机种子。随机种子的生成是获取运行时间的字符串,然后拿到字符串的哈希码作为随机种子传进去,这样每次生成的地图就可以保证不重复了。
完整代码:
public int width; //地图的宽度
public int height; //地图的高度
public string seed; //随机种子
public bool useRandomSeed; //是否使用随机中的Flag
[Range(0, 100)]
public int randomFillPercent; //填充百分比
int[,] map; //地图的信息
private void Start()
{
GenerateMap();
}
private void Update()
{
//测试点击鼠标生成新的地图
if (Input.GetMouseButtonDown(0))
{
GenerateMap();
}
}
/// <summary>
/// 生成地图
/// </summary>
void GenerateMap()
{
map = new int[width, height];
RandomFillMap();
for (int i = 0; i < 5; i++)
{
SmoothMap();
}
}
/// <summary>
/// 随机填充地图
/// </summary>
void RandomFillMap()
{
if (useRandomSeed)
{
seed = Time.time.ToString();
}
System.Random pseudoRandom = new System.Random(seed.GetHashCode());
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
//将周围包括起来
if (x == 0 || x == width - 1 || y == 0 || y == height - 1)
{
map[x, y] = 1;
}
else
{
map[x, y] = (pseudoRandom.Next(0, 100) < randomFillPercent) ? 1 : 0;
}
}
}
}
/// <summary>
/// 让地图变得平滑
/// </summary>
void SmoothMap()
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
int neighbourWallTiles = GetSurroundingWallCount(x, y);
///这里的数字4和不等式的等于号是否要加,自己可以尝试,然后看运行的效果。
if (neighbourWallTiles > 4)
{
map[x, y] = 1;
}
else if (neighbourWallTiles < 4)
{
map[x, y] = 0;
}
}
}
}
/// <summary>
/// 获取周围的墙的数量,(这里的墙指的就是Map【x,y】 = 0)
/// </summary>
/// <param name="gridX">坐标x</param>
/// <param name="gridY">坐标y</param>
/// <returns></returns>
int GetSurroundingWallCount(int gridX, int gridY)
{
int wallCount = 0;
for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX++)
{
for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY++)
{
if (neighbourX >= 0 && neighbourX < width && neighbourY >= 0 && neighbourY < height)
{
if (neighbourX != gridX || neighbourY != gridY)
{
wallCount += map[neighbourX, neighbourY];
}
}
else
{
wallCount++;
}
}
}
return wallCount;
}
/// <summary>
/// 绘制
/// </summary>
private void OnDrawGizmos()
{
if (map != null)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Gizmos.color = (map[x, y] == 1) ? Color.black : Color.white;
Vector3 pos = new Vector3(-width / 2 + x + .5f, 0, -height / 2 + y + .5f);
Gizmos.DrawCube(pos, Vector3.one);
}
}
}
}
第一部分不多也比较好理解,就先讲到这里了,想往后学习的可以去上面的视频链接找到视频作者。