众所周知,小地图的制作在游戏里面的应用是非常广泛的,通过小地图我们可以实时获取玩家在世界场景中的信息,给玩家更好的体验。在unity中,我们可以通过新建相机,设置相机的正交模式和位置,深度等可以实现简易的小地图效果;也可以通过RawImage实现,但是会影响性能。这里我将介绍另外一种:创建图片,给图片贴图,实现和地形同步的小地图。
主要运用了Mesh和Texture2D。
首先,我们需要创建一个空对象(命名为Map),为了挂载生成地形的脚本。再创建一个UI Image图片作为我们的小地图图片(命名为miniMap)。
将DrawMap脚本挂载到Map上
这里也是可以手动调整颜色值的。
绘制地形的脚本:DrawMap
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class DrawMap : MonoBehaviour
{
//地形长,宽
[Range(0,250)]
public int len , wide ;
//网格
Mesh mesh;
//顶点辅助器
VertexHelper vh;
//纹理
Texture2D texture;
//颜色
[SerializeField] Color color1, color2;
private void Awake()
{
//根据尺寸创建地形
CreateMap(len,wide);
}
/// <summary>
/// 创建地形
/// </summary>
/// <param name="len">长</param>
/// <param name="wide">宽</param>
private void CreateMap(int len,int wide)
{
mesh = new Mesh();
vh = new VertexHelper();
texture = new Texture2D(len, wide);
for (int i = 0; i < len; i++)
{
for (int j = 0; j < wide; j++)
{
//通过柏林噪声计算地形的高度值(y值)
float y = Mathf.PerlinNoise(i * 0.04f, j * 0.04f) * 10;
//添加顶点并计算对应的uv坐标
vh.AddVert(new Vector3(i, y, j), Color.white, new Vector2(i / (len * 1.0f), j / (wide * 1.0f)));
//根据高度判断是否为水面 给纹理渲染不同的颜色
if (y > 4f)
{
texture.SetPixel(i, j, color2);
}
else
{
texture.SetPixel(i, j, color1);
}
//计算顶点下标连接路线
if (i < len - 1 && j < wide - 1)
{
vh.AddTriangle(i * wide + j, (i + 1) * wide + j + 1, (i + 1) * wide + j);
vh.AddTriangle(i * wide + j, i * wide + j + 1, (i + 1) * wide + j + 1);
}
}
}
//应用纹理
texture.Apply();
//绘制网格
vh.FillMesh(mesh);
GetComponent<MeshFilter>().mesh = mesh;
//给网格附上纹理
Material mat = new Material(Shader.Find("Standard"));
mat.mainTexture = texture;
GetComponent<MeshRenderer>().material = mat;
}
}
因为我们知道,Mesh网格绘制的顶点数不能超过65000个,所以这里我将地形的长宽做了一个限制,避免可能出现的报错。
然后通过Mathf类的柏林噪声方法(Mathf.PerlinNoise())计算出地形的高度值Y。这个Y值就是我们绘制地形,给地形贴纹理的依据,给小地图贴图的关键。因为一般游戏中都是根据地形的高度来分配相关的地貌的如山体、平地、河流等等。这里我们只设置简单的两种类型:地面和水面(河流)。
根据上面计算出来Y值判断,如果Y值大于4就说明是地面,否则就判定为水面。根据这个逻辑计算纹理的颜色分配,最后绘制地形网格,给定纹理,就可以生成地形了。
地形完成后,我们就要给小地图(miniMap)挂上MiniMap脚本,并手动将map拖到小地图脚本组件中。
小地图的脚本:MiniMap
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MiniMap : MonoBehaviour
{
[SerializeField]
Texture2D texture;
[SerializeField]
DrawMap map;
void Start()
{
texture = new Texture2D(1024, 1024);
//获取地形的顶点数组
Vector3[] verties = map.gameObject.GetComponent<MeshFilter>().mesh.vertices;
int len = map.len;
int wide = map.wide;
for (int x = 0; x < len; x++)
{
for (int z = 0; z < wide; z++)
{
//计算小地图的纹理
float y = verties[x*wide+z].y;
if(y>4f)
{
texture.SetPixel(x, z, Color.green);
}
else
{
texture.SetPixel(x, z, Color.blue);
}
}
}
//将上面的纹理应用
texture.Apply();
//创建新的精灵图给图片赋值
GetComponent<Image>().sprite = Sprite.Create(texture, new Rect(0, 0, wide, len), new Vector2(0.5f, 0.5f));
}
void Update()
{
}
}
这里通过获取绘制地形脚本中的mesh顶点数据,这样我们也就知道了Y值,同样也是根据这个Y值,来计算我们小地图的Texture2D贴图纹理。通过Sprite.Create()创建新的精灵图给我们的小地图图片赋值。
这样我们的最终效果就实现了。
最终效果: