unity3D游戏开发文档|路点寻路(unity3D)

路点寻路
第一步:现在场景上确认几个定点,并用Gizmos画出路线

首先在场景中确定几个空节点,放在一个父节点下面
将脚本绑在该父节点上
unity3D游戏开发文档|路点寻路(unity3D)
文章图片

画出来的效果:
unity3D游戏开发文档|路点寻路(unity3D)
文章图片

public class WayPoint : MonoBehaviour { //用一个数组对点进行存储 Transform[] points; public Transform[] Points { get { if(points == null) { points = new Transform[transform.childCount]; for (int i = 0; i < points.Length; i++) { points[i] = transform.GetChild(i); } } return points; } }// Start is called before the first frame update void Start() {}// Update is called once per frame void Update() {}//和update类似,也是每帧调用一次 //OnDrawGizmos是在代码编译完成时开始执行 private void OnDrawGizmos() { //Gizmos.DrawCube(Vector3.zero, Vector3.one); //划线的颜色 Gizmos.color = Color.red; for (int i = 0; i < Points.Length - 1; i++) { Gizmos.DrawLine(Points[i].position, Points[i + 1].position); } } }

【unity3D游戏开发文档|路点寻路(unity3D)】思考:
  1. 用数组对行动的点进行存储
  2. OnDrawGizmos() 在代码编译的时候执行,然后调用属性函数,获取到用于画线的点
  3. 每帧执行,每帧都在画线
第二步:物体的移动 主要用的api:
  1. transform.LookAt() 物体的朝向
  2. Vector3.MoveTowards(起点坐标,终点坐标,最大步长),当距离终点较远时,每步走最大的步长的长度,返回要移动的位置
  3. Vector3.Distance() 计算两个向量的间距
  4. Vector3.LerpVector3 a, Vector3 b, float t)插值
  5. Vector3.Cross() 法线
public class Patrol: MonoBehaviour { //当前怪物所在的路径,以及路径信息 public WayPoint way; //要移动到的路径点的下标 int targetIndex; //移动速度 public float moveSpeed; //旋转的速度 public float rotateSpeed; //要旋转的目标的朝向 Vector3 targetDir; // Start is called before the first frame update void Start() { transform.position = way.Points[0].position; transform.LookAt(way.Points[1]); targetIndex = 1; targetDir = way.Points[targetIndex].position - transform.position; }// Update is called once per frame void Update() {//transform.position += transform.forward * moveSpeed * Time.deltaTime; //maxDistanceDelta最大的步长 //Vector3.MoveTowards(起点坐标,终点坐标,最大步长),当距离终点较远时,每步走最大的步长的长度,返回要移动的位置 //当靠近或抵达终点时,只会返回终点的坐标,不会越过 transform.position = Vector3.MoveTowards(transform.position, way.Points[targetIndex].position, moveSpeed * Time.deltaTime); //Rotate(); if (Vector3.Distance(transform.position, way.Points[targetIndex].position) <= 0.1f) { targetIndex++; if (targetIndex >= way.Points.Length) { this.enabled = false; return; //用return的原因是,更改enabled状态后,下一帧不会执行,这一帧会执行完 } targetDir = way.Points[targetIndex].position - transform.position; // transform.LookAt(way.Points[targetIndex]); }transform.forward = Vector3.Lerp(transform.forward, targetDir, rotateSpeed * Time.deltaTime); }void Rotate() { Vector3 dir = way.Points[targetIndex].position - transform.position; float angle = Vector3.Angle(transform.forward, dir); angle = Mathf.Min(angle, rotateSpeed); transform.Rotate(Vector3.Cross(transform.forward, dir)* angle); } }

思路:
主要是关于人物的向目标点的移动和移动过程中的转向问题
移动的问题:
  1. 首先要知道路线,可以通过静态的绑定或者动态的查找,主要是获取绑定上面路线脚本的节点,通过脚本组件里面的属性获取到路线点
  2. 定义一个变量存储要到达的点在数组中的的下标,定义移动的速度
  3. 在start里面,首先设置物体的位置到第一个点,物体朝向第二个点,并且将下标加一
  4. 最重要的就是移动,有两种方法:
    第一种:最简单的,因为角度确定,移动是向前的,所以每帧去加上一个向前的向量即可
    第二种:利用Vector3.MoveTowardsAPI,可以避免因为速度过快,而超出去的情况
  5. 转向的校验:通过物体与目标点的向量的间距来判断是否转向,转向将下标加一,并且还要校验下标是否越界,如果越界,就关掉脚本的活性,并且跳出语句。
转向的问题:
  1. 转向的问题也有几种解决办法
    第一种:直接通过transform.LookAt()来更改物体的朝向
    第二种:写一个更改角度的函数,首先获取物体与目标点间的向量,然后计算出物体向前的向量与获取向量的夹角,设置一个旋转角度,根据旋转角度不停的旋转方向,直到夹角为0;
    注意:①这里在旋转的时候,不能绕着y轴旋转,而是绕着法向量进行旋转,因为角度有正有负
    ? ②可以优化的地方,在旋转之前,将两向量的夹角与设定的旋转的角度进行比较,选择较小的角进行旋转,可以避免旋转过的情况出现
    第三种:插值的方法,将forword的方向与目标点的方向,进行插值改变

    推荐阅读