unity3D游戏开发文档|路点寻路(unity3D)
路点寻路
第一步:现在场景上确认几个定点,并用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);
}
}
}
【unity3D游戏开发文档|路点寻路(unity3D)】思考:
- 用数组对行动的点进行存储
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
的方向与目标点的方向,进行插值改变
推荐阅读
- 深入理解Go之generate
- 游戏IP(立足于玩家情感的粉丝经济)
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- 人生游戏--是游戏,还是人生()
- 「按键精灵安卓版」关于全分辨率脚本的一些理解(非游戏app)
- (小说)月流水几亿的火爆游戏养成记
- 游戏治愈了我无聊之症
- 我的软件测试开发工程师书单
- echart|echart 双轴图开发
- 生活与游戏日记(第182篇)(〔成长瞬间〕关注解决问题2019.10)