路点寻路
第一步:现在场景上确认几个定点,并用Gizmos 画出路线
首先在场景中确定几个空节点,放在一个父节点下面
将脚本绑在该父节点上
画出来的效果:
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);
}
}
}
思考:
- 用数组对行动的点进行存储
OnDrawGizmos () 在代码编译的时候执行,然后调用属性函数,获取到用于画线的点- 每帧执行,每帧都在画线
第二步:物体的移动
主要用的api :
transform.LookAt() 物体的朝向Vector3.MoveTowards (起点坐标,终点坐标,最大步长),当距离终点较远时,每步走最大的步长的长度,返回要移动的位置Vector3.Distance() 计算两个向量的间距Vector3.Lerp (Vector3 a , Vector3 b, float t)插值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);
}
}
思路:
主要是关于人物的向目标点的移动和移动过程中的转向问题
移动的问题:
-
首先要知道路线,可以通过静态的绑定或者动态的查找,主要是获取绑定上面路线脚本的节点,通过脚本组件里面的属性获取到路线点 -
定义一个变量存储要到达的点在数组中的的下标,定义移动的速度 -
在start里面,首先设置物体的位置到第一个点,物体朝向第二个点,并且将下标加一 -
最重要的就是移动,有两种方法: 第一种:最简单的,因为角度确定,移动是向前的,所以每帧去加上一个向前的向量即可 第二种:利用Vector3.MoveTowards API,可以避免因为速度过快,而超出去的情况 -
转向的校验:通过物体与目标点的向量的间距来判断是否转向,转向将下标加一,并且还要校验下标是否越界,如果越界,就关掉脚本的活性,并且跳出语句。
转向的问题:
-
转向的问题也有几种解决办法 第一种:直接通过transform.LookAt() 来更改物体的朝向 第二种:写一个更改角度的函数,首先获取物体与目标点间的向量,然后计算出物体向前的向量与获取向量的夹角,设置一个旋转角度,根据旋转角度不停的旋转方向,直到夹角为0; 注意:①这里在旋转的时候,不能绕着y轴旋转,而是绕着法向量进行旋转,因为角度有正有负 ? ②可以优化的地方,在旋转之前,将两向量的夹角与设定的旋转的角度进行比较,选择较小的角进行旋转,可以避免旋转过的情况出现 第三种:插值的方法,将forword 的方向与目标点的方向,进行插值改变
|