上一节介绍了Seek以及Flee,和Seek相对应的还有Arrival操控力行为
Arrival 和Seek的区别
-
Seek行为对于让一个智能体向正确方向移动很有用,但是很多情况是希望智能体能缓缓地停在目标位置,而Seek行为是到达Target以后再其周围来回摆动。
-
Arrive 行为是一种操控智能体慢慢减速直至停在目标位置的行为。
Arrive原理(方案一)
Paste_Image.png- 代码实现:
- 由于Arrive行为大致和Seek一致,于是我们在Seek的代码上添加减速半径slowDownRadius、物体与Target的距离distance。
-
距离:distance=toTarget.magnitude;
-
接着对距离进行判断,如果距离大于减速半径说明不需要减速,小于则需要减速。
- 场景中的实现
- 设置最大速度,减速半径,以及Target目标点
- 方案二:
- 使用distance/slowdownRadius,从1-0变化的,且是线性变化,可以使得速度的改变是平滑的。
- 场景演示:
-
Arrival AI代码:
public class Arrival : MonoBehaviour {
public float max_velocity; //游戏物体运动的最大速度
public Transform Target; //目标物体的位置
public Vector3 velocity; //物体的速度public float slowDownRadius; //减速半径 private float timer; //计时器 private List<Vector3> pathList; //绘制逃离路线 void Start() { max_velocity = 8; timer = 0; pathList = new List<Vector3>(); pathList.Add(transform.position); }
void Update()
{timer += Time.deltaTime; if (timer > 0.2f) { timer = 0; pathList.Add(transform.position); } //操控力的定义 Vector3 steeringForce = new Vector3(0, 0, 0); //首先要判断他们之间的距离是否到了半径之内 Vector3 toTarget = Target.position - this.transform.position; //之后求距离 float distance = toTarget.magnitude; ////第一种方案,渐渐的减速 //if (distance > slowDownRadius) //{ // //如果大于减速半径就是Seek行为 // Vector3 desiredVelocity = (Target.position - transform.position).normalized * max_velocity; // //操控力 // steeringForce = desiredVelocity - velocity; //} //else //{ // //如果小于减速半径就是Arrival行为 // Vector3 desiredVelocity = toTarget - velocity; // //操控力 // steeringForce = desiredVelocity - velocity; //} //第二种方案,突然的减速 if (distance > slowDownRadius) { //如果大于减速半径就是Seek行为 Vector3 desiredVelocity = (Target.position - transform.position).normalized * max_velocity; //操控力 steeringForce = desiredVelocity - velocity; } else { //如果小于减速半径就是Arrival行为,系数是(distance / slowDownRadius) Vector3 desiredVelocity = -toTarget.normalized * max_velocity * (distance / slowDownRadius); //操控力 steeringForce = desiredVelocity - velocity; } //加速度acc,速度除以质量,这里质量为1 Vector3 acc = steeringForce / 1; velocity += acc * Time.deltaTime; transform.position += velocity * Time.deltaTime; //如果速度的模大于0.01,说明有速度,然后设置偏转,进行弧线插值计算 if (velocity.magnitude > 0.01f) { //设置偏转,得到中间的插值,向前的力 Vector3 newForward = Vector3.Slerp(transform.forward, velocity, Time.deltaTime); newForward.y = 0; transform.forward = newForward; } for (int i = 0; i < pathList.Count - 1; i++) { Debug.DrawLine(pathList[i], pathList[i + 1], Color.red); }
}
}
网友评论