初始化地图的代码如下:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class PerlinNoiseMap : MonoBehaviour
{
int w, h;//宽,高
float row, col;//行,列
VertexHelper vh;
[SerializeField]
Texture2D texture2D;//地图的材质
public void Init(int r, int c)
{
row = r;
col = c;
w = 100;
h = 100;
vh = new VertexHelper();
Mesh mesh = new Mesh();
for (int i = 0; i <= w; i++)
{
for (int j = 0; j <= h; j++)
{
//用PerlinNoise计算地图的高度
float y = Mathf.PerlinNoise((i + row * w) * 0.02f, (j + col * h) * 0.02f) * 30;
//计算u,v值从而确定贴图
float u = i * 1.0f / w;
float v = j * 1.0f / h;
if (y <= 10)//设置最低高度
{
y = 0;
}
//解决边界有痕的问题
if (row % 2 == 0)
{
u = 1 - u;
}
if (col % 2 == 0)
{
v = 1 - v;
}
//绘制地图
vh.AddVert(new Vector3(i, y, j), Color.white, new Vector2(u, v));
if (i < w && j < h)
{
vh.AddTriangle(i * (h + 1) + j, i * (h + 1) + j + 1, (i + 1) * (h + 1) + j + 1);
vh.AddTriangle(i * (h + 1) + j, (i + 1) * (h + 1) + j + 1, (i + 1) * (h + 1) + j);
}
}
}
vh.FillMesh(mesh);
GetComponent<MeshFilter>().mesh = mesh;
Material mat = new Material(Shader.Find("Standard"));
mat.mainTexture = texture2D;
GetComponent<MeshRenderer>().material = mat;
GetComponent<MeshCollider>().sharedMesh = mesh;
}
List<Vector3> vertics = new List<Vector3>();//顶点的集合
public void Refresh(int r, int c)
{
row = r;
col = c;
vertics.Clear();
GetComponent<MeshFilter>().mesh.GetVertices(vertics);
for (int i = 0; i <= w; i++)
{
for (int j = 0; j <= h; j++)
{
float y = Mathf.PerlinNoise((i + w * r) * 0.02f, (j + h * c) * 0.02f) * 30;
if (y <= 10)
{
y = 0;
}
float u, v;
if (row % 2 == 0)
{
u = 1 - (i * 1.0f) / w;
}
else
{
u = (i * 1.0f) / w;
}
if (col % 2 == 0)
{
v = 1 - (j * 1.0f) / h;
}
else
{
v = (j * 1.0f) / h;
}
Vector3 point = vertics[i * (h + 1) + j];
point.y = y;
vertics[i * (h + 1) + j] = point;
}
}
GetComponent<MeshFilter>().mesh.vertices = vertics.ToArray();
}
}
下面是地图刷新和玩家移动的代码
using System.Collections.Generic;
using UnityEngine;
public class RefreshMap : MonoBehaviour
{
[SerializeField]
GameObject tield;//地图模板
[SerializeField]
GameObject player;//玩家
public List<TieldData> tieldDatas = new List<TieldData>();//地图数据的集合
List<GameObject> tislds = new List<GameObject>();//地图模块的集合
float orgX, orgY;//地图的初始位置
int[,] tieldIndex = new int[9, 2];//地图下标的集合
int curX, curZ;//地图的初始下标
public int tieldSize = 100;//地图的大小(宽,高)
Dictionary<string, GameObject> dicTield = new Dictionary<string, GameObject>();//缓存地图的字典
// Start is called before the first frame update
void Start()
{
orgX = -tieldSize;
orgY = -tieldSize;
//生成九宫格地图
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
GameObject item;
if (i == 0 && j == 0)
{
item = tield;
}
else
{
item = Instantiate(tield);
}
item.name = i.ToString() + "," + j.ToString();
tislds.Add(item);
item.GetComponent<PerlinNoiseMap>().Init(i, j);
item.transform.SetParent(transform);
item.transform.localPosition = new Vector3(i * tieldSize + orgX, 0, j * tieldSize + orgY);
TieldData tieldData = new TieldData();
tieldData.r = i;
tieldData.c = j;
tieldData.go = item;
tieldDatas.Add(tieldData);
}
}
}
//缓存地图模块的下标
void TieldIndex(int x, int z)
{
tieldIndex[0, 0] = x - 1;
tieldIndex[0, 1] = z - 1;
tieldIndex[1, 0] = x - 1;
tieldIndex[1, 1] = z;
tieldIndex[2, 0] = x - 1;
tieldIndex[2, 1] = z + 1;
tieldIndex[3, 0] = x;
tieldIndex[3, 1] = z - 1;
tieldIndex[4, 0] = x;
tieldIndex[4, 1] = z;
tieldIndex[5, 0] = x;
tieldIndex[5, 1] = z + 1;
tieldIndex[6, 0] = x + 1;
tieldIndex[6, 1] = z - 1;
tieldIndex[7, 0] = x + 1;
tieldIndex[7, 1] = z;
tieldIndex[8, 0] = x + 1;
tieldIndex[8, 1] = z + 1;
dicTield.Clear();
for (int i = 0; i < tieldIndex.GetLength(0); i++)
{
string key = tieldIndex[i, 0].ToString() + "," + tieldIndex[i, 1].ToString();
dicTield.Add(key, null);
}
}
List<GameObject> temobj = new List<GameObject>();
// Update is called once per frame
void Update()
{
Move();
//计算玩家的位置
Vector3 off = player.transform.position - new Vector3(orgX, 0, orgY);
//计算玩家在九宫格地图上的比例
int x = Mathf.FloorToInt(off.x / tieldSize);
int z = Mathf.FloorToInt(off.z / tieldSize);
//计算玩家在小地图上的比例
Vector3 leftBottom = new Vector3(orgX + (x - 1) * tieldSize, 0, orgY + (z - 1) * tieldSize);
Vector3 tempPos = player.transform.localPosition - leftBottom;
float pivotX = tempPos.x / (3 * tieldSize);
float pivotY = tempPos.z / (3 * tieldSize);
//设置小地图的中心点和位置
GameObject.Find("Canvas/Panel/Mask/MiniMap").GetComponent<RectTransform>().pivot = new Vector2(pivotX,pivotY);
GameObject.Find("Canvas/Panel/Mask/MiniMap").GetComponent<RectTransform>().localPosition = Vector3.zero;
if (x == curX && z == curZ) return;
TieldIndex(x, z);
for (int i = 0; i < tislds.Count; i++)
{
string key = tislds[i].name;
if (dicTield.ContainsKey(key))
{
dicTield[key] = tislds[i];
}
else
{
temobj.Add(tislds[i]);
}
}
for (int i = 0; i < tieldIndex.GetLength(0); i++)
{
string key = tieldIndex[i, 0].ToString() + "," + tieldIndex[i, 1].ToString();
TieldData tieldData = tieldDatas[i];
tieldData.r = tieldIndex[i, 0];
tieldData.c = tieldIndex[i, 1];
if (dicTield[key] == null)
{
GameObject item = temobj[0];
item.transform.localPosition = new Vector3(tieldIndex[i, 0] * tieldSize + orgX, 0,
tieldIndex[i, 1] * tieldSize + orgY);
item.name = key;
dicTield[key] = item;
item.GetComponent<PerlinNoiseMap>().Refresh(tieldIndex[i, 0], tieldIndex[i, 1]);
temobj.RemoveAt(0);
}
tieldData.go = dicTield[key];
}
tieldDatas.Sort((a, b) =>
{
return (int)(a.r - b.r);
});
tieldDatas.Sort((a, b) =>
{
return (int)(a.c - b.c);
});
GameObject.Find("Canvas/Panel/Mask").GetComponent<MiniMap>().RefreshMap(tieldDatas);
curX = x;
curZ = z;
}
private void Move()//玩家移动
{
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
player.transform.Translate(new Vector3(0, 0, y) * Time.deltaTime * 10);
player.transform.Rotate(new Vector3(0, x, 0) * Time.deltaTime * 100);
}
}
//地图模块的数据类
public class TieldData
{
public int r;
public int c;
public GameObject go;
}
下面是小地图刷新的代码:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MiniMap : MonoBehaviour
{
public List<Image> images; //小地图图片的集合
List<Texture2D> texture2Ds = new List<Texture2D>();//小地图贴图的集合
public RectTransform miniMap;//小地图的父物体
//每块小地图的大小(宽,高)
int w = 100;
int h = 100;
private void Awake()
{
for (int i = 0; i < images.Count; i++)
{
Texture2D texture = new Texture2D(w, h);
texture2Ds.Add(texture);
}
}
public void RefreshMap(List<TieldData> tieldDatas)
{
for(int i =0;i<images.Count;i++)
{
Texture2D texture2D = tieldDatas[i].go.GetComponent<MeshRenderer>().material.mainTexture as Texture2D;
List<Vector3> points = new List<Vector3>();
tieldDatas[i].go.GetComponent<MeshFilter>().mesh.GetVertices(points);
int row = tieldDatas[i].r;
int col = tieldDatas[i].c;
for (int x = 0;x<=100;x++)
{
for (int z = 0; z <= 100; z++)
{
float y = points[x * 101 + z].y;
if (y > 10)
{
int u, v;
if (row % 2 == 0)
{
u = w - x;
}
else
{
u = x;
}
if (col % 2 == 0)
{
v = h - z;
}
else
{
v = z;
}
texture2Ds[i].SetPixel(x, z,texture2D.GetPixel(u,v));
}
else
{
texture2Ds[i].SetPixel(x, z, Color.blue);
}
}
}
texture2Ds[i].Apply();
images[i].sprite = Sprite.Create(texture2Ds[i],new Rect(0,0,w,h),new Vector2(0.5f,0.5f));
}
}
float scale = 1.0f;
// Update is called once per frame
void Update()
{
//鼠标滚轮控制地图缩放
if (Input.GetAxis("Mouse ScrollWheel") != 0)
{
scale += Input.GetAxis("Mouse ScrollWheel");
miniMap.localScale = new Vector3 (scale,scale,scale);
}
}
}
相机丝滑跟随的代码:
using UnityEngine;
/// <summary>
/// 挂载在相机上
/// </summary>
public class CameraMove : MonoBehaviour
{
public GameObject player;//玩家
Vector3 pos;//相对位置
// Start is called before the first frame update
void Start()
{
pos = new Vector3(0,12,-8);
}
// Update is called once per frame
void Update()
{
//设置相机的位置和朝向
transform.position = Vector3.Lerp(transform.position,player.transform.position + pos,Time.deltaTime / 2);
Quaternion qua = Quaternion.LookRotation(player.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation,qua,Time.deltaTime);
}
}
注意事项:
需要添加一个Mask组件