1.土地的生成 :创建空对象,挂载以下脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
using UnityEngine.UIElements;
[RequireComponent(typeof(MeshFilter), typeof(MeshCollider), typeof(MeshRenderer))]
//柏林噪声地图
public class BoLingMaps : MonoBehaviour
{
//长
public int x = 100;
//款
public int y = 100;
//存储生成出的物品
public List<GameObject> bodyList = new List<GameObject>();
//水面高度
[Range(-5,5)]public float waterHeight = 2f;
// 植物或矿石的预制件
public GameObject[] objectsToSpawn;
//要生成的物品
public int numberOfObjects = 100;
//存储水面上面的顶点的集合
private List<Vector3> verticesPositions;
VertexHelper vh;
Mesh mesh;
private void Awake()
{
vh = new VertexHelper();
verticesPositions = new List<Vector3>();
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
float rx = Random.Range(0.02f, 0.02f);
float ry = Random.Range(0.02f, 0.02f);
float hight = Mathf.PerlinNoise(i * 0.02f + rx, j * 0.02f + ry);
float uvx = (float)i / (x - 1);
float uvy = (float)j / (y - 1);
Vector3 pos = new Vector3(i, hight*10, j);
vh.AddVert(pos, Color.green, new Vector2(uvx, uvy));
if (pos.y >= waterHeight)
{
//存储水面上面的顶点,用来生成物品
verticesPositions.Add(pos);
}
if (i != x - 1 && j != y - 1)
{
vh.AddTriangle(i * y + j, i * y + j + 1, (i + 1) * y + j + 1);
vh.AddTriangle(i * y + j, (i + 1) * y + j + 1, (i + 1) * y + j);
}
}
}
mesh = new Mesh();
vh.FillMesh(mesh);
GetComponent<MeshFilter>().mesh = mesh;
CreateWater();
SpawnObjects();
}
//绘制水面
void CreateWater()
{
GameObject water = GameObject.CreatePrimitive(PrimitiveType.Plane);
water.transform.localScale = new Vector3(x / 10f, 1, y / 10f);
water.transform.position = new Vector3(x / 2f,waterHeight, y / 2f);
water.AddComponent<NavMeshObstacle>().carving = true;
water.GetComponent<Renderer>().material = new Material(Shader.Find("Standard"))
{
color = Color.blue
};
}
//生成地图装饰
void SpawnObjects()
{
for (int i = 0; i < numberOfObjects; i++)
{
if (verticesPositions.Count > 0)
{
//随机模型
GameObject objectToSpawn = objectsToSpawn[Random.Range(0, objectsToSpawn.Length)];
objectToSpawn.transform.localScale = Vector3.one * 3;
//随机位置
Vector3 randomVertex = verticesPositions[Random.Range(0, verticesPositions.Count)];
GameObject obj = Instantiate(objectToSpawn, randomVertex, Quaternion.identity);
bodyList.Add(obj);
}
}
}
}
如图所示:框选处放想生成的预制体,空对象挂载NavMeshSourceTag
2.角色的创建:如下图,挂载LocalNavMeshBuilder脚本,CubeMove是移动脚本(主要是射线点击地面移动)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEditor.Experimental.GraphView.GraphView;
using UnityEngine.AI;
public class CubeMove : MonoBehaviour
{
public Ray ray;//声明射线
public NavMeshAgent nav;//获取NavMeshAgent
// Start is called before the first frame update
void Start()
{
nav = this.GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
射线点击地面移动
//if (Input.GetKeyDown(KeyCode.Mouse0)) //如果鼠标左键点击
//{
// ray = Camera.main.ScreenPointToRay(Input.mousePosition);//射线从鼠标在屏幕坐标中发射
// RaycastHit hit;
// //存储射线对象内的投射命中点的信息到RaycastHit
// if (Physics.Raycast(ray, out hit))
// {
// Vector3 points = hit.point;
// //transform.LookAt(points);
// //让导航对像在移动时始终面向导航坐标位置
// nav.SetDestination(points);
// //利用导航到指定坐标点位置
// }
//}
}
private void OnTriggerEnter(Collider other)
{
//判断碰撞到的物品以便后续逻辑
if(other.tag == "Body")
{
print(other.gameObject.name);
}
}
}
注意:LocalNavMeshBuilder和NavMeshSourceTag都是动态烘焙地形包的脚本
3.两种小地图的制作:
(1).左侧:人物Image始终在中间,Slider控制小地图Image缩放,地图Image移动
(2).右侧:小地图Image不变,人物Image移动(注意挂载脚本的Image的Pivot设置为(0,0))
如图是UI搭建:
小地图一:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.UI;
//Image有Mask,两个Image子类,一个挂脚本,一个作为中心点
public class MapminiOne : MonoBehaviour, IPointerClickHandler
{
//创建地图脚本的引用,用来获取其中的装饰物集合
public BoLingMaps boLingMaps;
//玩家
public Transform player;
//地图的rectTransform
private RectTransform _rectTransform;
//玩家的对象
public NavMeshAgent nav;
//控制缩放的Slider
public Slider Slider;
private void Awake()
{
Slider.value = 1;
_rectTransform = GetComponent<RectTransform>();
}
private void Start()
{
//生成地图装饰物
for (int i = 0; i < boLingMaps.bodyList.Count; i++)
{
GameObject bodyimg = GameObject.Instantiate(Resources.Load<GameObject>("bodyimg"), transform);
if (boLingMaps.bodyList[i].name.Contains("Tou"))
{
bodyimg.GetComponent<Image>().color = Color.red;
}
if (boLingMaps.bodyList[i].name.Contains("Tui"))
{
bodyimg.GetComponent<Image>().color = Color.yellow;
}
if (boLingMaps.bodyList[i].name.Contains("YiFu"))
{
bodyimg.GetComponent<Image>().color = Color.blue;
}
if (boLingMaps.bodyList[i].tag.Contains("Grass"))
{
bodyimg.GetComponent<Image>().color = new Color(0f, 0.4f, 0f, 1f);
}
if (boLingMaps.bodyList[i].tag.Contains("Stone"))
{
bodyimg.GetComponent<Image>().color = Color.gray;
}
if (boLingMaps.bodyList[i].tag.Contains("Food"))
{
bodyimg.GetComponent<Image>().color = Color.red;
}
float x = boLingMaps.bodyList[i].transform.position.x / 100 * _rectTransform.sizeDelta.x - 200;//减去半径
float y = boLingMaps.bodyList[i].transform.position.z / 100 * _rectTransform.sizeDelta.y - 200;
bodyimg.transform.localPosition = new Vector2(x, y);
}
}
private void Update()
{
//实时获取大地图的比例(100是柏林噪声地图的宽高)
float x = nav.transform.position.x / 100;
float y = nav.transform.position.z / 100;
//中心点跟随移动
_rectTransform.pivot = new Vector2(x, y);
//滑动条控制缩放
_rectTransform.localScale = Vector3.one * Slider.value;
//滚轮控制缩放
if (Input.GetAxis("Mouse ScrollWheel") != 0)
{
_rectTransform.localScale += Vector3.one * Input.GetAxis("Mouse ScrollWheel");
}
}
public void OnPointerClick(PointerEventData eventData)
{
//mapImage 的标签
if (eventData.pointerPressRaycast.gameObject.tag == "Map")
{
var isClick =
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, eventData.position, null,
out var point);
float x = point.x / _rectTransform.sizeDelta.x * 100;
float y = point.y / _rectTransform.sizeDelta.y * 100;
var endpos = player.position + new Vector3(x, 0, y);
nav.SetDestination(endpos);
}
//根据装饰物在场景的位置把位置映射在小地图上 BodyImage 是生成的装饰物image预制体的标签
if (eventData.pointerPressRaycast.gameObject.tag == "BodyImage")
{
Debug.Log(eventData.pointerPressRaycast.gameObject.name);
float x = eventData.pointerPressRaycast.gameObject.transform.localPosition.x / _rectTransform.sizeDelta.x * 100;
float y = eventData.pointerPressRaycast.gameObject.transform.localPosition.y / _rectTransform.sizeDelta.y * 100;
var endpos = player.position + new Vector3(x, 0, y);
nav.SetDestination(endpos);
}
}
}
小地图二:
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class MapminiTwo : MonoBehaviour, IPointerClickHandler
{
//创建地图脚本的引用,用来获取其中的装饰物集合
public BoLingMaps boLingMaps;
//代表人物的图片
public Image myImage;
private RectTransform _rectTransform;
//移动的主角
public NavMeshAgent nav;
void Awake()
{
_rectTransform = GetComponent<RectTransform>();
}
private void Start()
{
for (int i = 0; i < boLingMaps.bodyList.Count; i++)
{
GameObject bodyimg = GameObject.Instantiate(Resources.Load<GameObject>("bodyimg"), transform);
if (boLingMaps.bodyList[i].name.Contains("Tou"))
{
bodyimg.GetComponent<Image>().color = Color.red;
}
if (boLingMaps.bodyList[i].name.Contains("Tui"))
{
bodyimg.GetComponent<Image>().color = Color.yellow;
}
if (boLingMaps.bodyList[i].name.Contains("YiFu"))
{
bodyimg.GetComponent<Image>().color = Color.blue;
}
if (boLingMaps.bodyList[i].tag.Contains("Grass"))
{
bodyimg.GetComponent<Image>().color = new Color(0f, 0.4f, 0f, 1f);
}
if (boLingMaps.bodyList[i].tag.Contains("Stone"))
{
bodyimg.GetComponent<Image>().color = Color.gray;
}
if (boLingMaps.bodyList[i].tag.Contains("Food"))
{
bodyimg.GetComponent<Image>().color = Color.red;
}
float x = boLingMaps.bodyList[i].transform.position.x / 100 * _rectTransform.sizeDelta.x;
float y = boLingMaps.bodyList[i].transform.position.z / 100 * _rectTransform.sizeDelta.y;
bodyimg.transform.localPosition = new Vector2(x, y);
}
}
//点击ui人物移动
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.pointerPressRaycast.gameObject.tag == "Map")
{
//获取点击的坐标
var isClicked =
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, eventData.position, null,
out var point);
//通过点击位置在小地图上的位置比例×实际的地图宽高,计算出3D坐标的位置
float x = point.x / _rectTransform.sizeDelta.x * 100;
float y = point.y / _rectTransform.sizeDelta.y * 100;
var endpos = new Vector3(x, 0, y);
//导航到对应位置
nav.SetDestination(endpos);
}
if (eventData.pointerPressRaycast.gameObject.tag == "BodyImage")
{
Debug.Log(eventData.pointerPressRaycast.gameObject.name);
float x = eventData.pointerPressRaycast.gameObject.transform.localPosition.x / _rectTransform.sizeDelta.x * 100;
float y = eventData.pointerPressRaycast.gameObject.transform.localPosition.y / _rectTransform.sizeDelta.y * 100;
var endpos = new Vector3(x, 0, y);
nav.SetDestination(endpos);
}
}
//人物移动映射到小地图
void Update()
{
//实时获取游戏人物在大地图的比例,×地图宽高,给红点图片赋值
float x = nav.transform.position.x / 100 * _rectTransform.sizeDelta.x;
float y = nav.transform.position.z / 100 * _rectTransform.sizeDelta.y;
myImage.transform.localPosition = new Vector2(x, y);
}
}