最近学了Unity3D的自带寻路Navmesh,觉得挺好用的,所以写出来和大家分享一下。
自带寻路Navmesh的三大组件:
1.Nav Mesh Agent:主要挂在寻路物体上
2.Off Mesh Link:实现区域转移功能(例如,有时不一定只是在地面上进行寻路,可能有些高高的平台,平台与地面是不相连的,使用该组件可以跳到平台上)
3.Nav Mesh Obstacle:主要挂在障碍物上
通过Navmesh可以实现自动寻路,爬楼梯,跳跃等功能。先上个效果图。
下面讲一下制作流程
首先从官网下载士兵模型,然后如下添加NavmeshAgent组件,无需加刚体(而且感觉加了刚体会出现鬼畜的现象,但是有时又正常),无需调整
然后建立一个Plane,在Navgation界面如下设置,然后Bake
上网下载桥的3D模型然后做几个Cube形成高低楼层,如上Bake。
为主角添加TestBake.cs脚本让主角走到鼠标点击的点
public class TestBake : MonoBehaviour {
private NavMeshAgent agent;
private Animator animation1;
void Start()
{
//获取组件
agent = GetComponent<NavMeshAgent>();
animation1 = GetComponent<Animator>();
}
void Update()
{
if(Bridge.Open == false)//吊桥相关后面解释
{
agent.areaMask = -1;
}
else
{
agent.areaMask = 1;
}
//鼠标左键点击
if (Input.GetMouseButtonDown(0))
{
//摄像机到点击位置的的射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.collider.name);
//判断点击的是否地形
/*
if (!hit.collider.name.Equals("Plane"))
{
return;
}
*/
//点击位置坐标
Vector3 point = hit.point;
Debug.Log(point);
//转向
transform.LookAt(new Vector3(point.x, point.y, point.z));
//设置寻路的目标点
agent.SetDestination(point);
}
}
//播放动画,判断是否到达了目的地,播放空闲或者跑步动画
if (agent.remainingDistance < 0.5f)
{
animation1.Play("idle");
}
else
{
animation1.Play("run");
}
}
}
这时人物已经可以随着你的鼠标点击点自动寻路了
但是你会发现人物不会爬楼梯,你需要为楼梯添加如下组件Off Mesh Link,新建两个点作为起点终点,这里我用两个小正方体做演示,实际游戏应该使用空物体,Bake一下会出现下图的路径。
如果想要实现向上跳,需要像上楼梯一样操作添加
向下跳就简单一点,为物体如下设置即可,Unity会自动帮你计算可以下跳的地方及路线,但是中间有间隔的不会有下跳的路线(如下图的绿色和黄色块之间,只能通过Off Mesh Link实现(上面的方法))
但是我们可以设置下跳的高度以及跳跃的水平距离
然后设置一下多路导航路线,加入Red,Blue,Green,Bridge层,如下设置
建立其他Plane作为路线,在Navigation里面设置相应的层如下(以蓝色层为例)
然后建立三个小兵,颜色为蓝,绿,红。设置如下(以红色为例)
然后添加Solider.cs //其实大致和TestBake差不多只是Solider没有动画而且多了delta为了防止和士兵碰撞
public class Solider : MonoBehaviour
{
public float delta = 0.5f;
private NavMeshAgent agent;
// Use this for initialization
void Start()
{
//获取组件
agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
//鼠标左键点击
if (Input.GetMouseButtonDown(0))
{
//摄像机到点击位置的的射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.collider.name);
//判断点击的是否地形
/*
if (!hit.collider.name.Equals("Plane"))
{
return;
}
*/
//点击位置坐标
Vector3 point = hit.point;
Debug.Log(point);
//转向
transform.LookAt(new Vector3(point.x, point.y, point.z));
//设置寻路的目标点
point.x += delta;
point.z += delta;
agent.SetDestination(point);
}
}
}
}
public class Bridge : MonoBehaviour {
public static bool Open = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetKeyDown(KeyCode.Space))//检测空格键按下
Open = !Open;//切换吊桥状态
if(Open == true)
{
this.transform.rotation = Quaternion.Euler(0, 0, 30);//吊起吊桥
}
else if(Open == false)
{
this.transform.rotation = Quaternion.Euler(0, 0, 0);//下降吊桥
}
}
}
if(Bridge.Open == false)
{
agent.areaMask = -1;//所有层均可通过
}
else
{
agent.areaMask = 1;//只通过行走层
}