上一篇我们讲到关于 BehaviorAgent 的派生类但是仅仅开个头,在本篇中我们会详细讲解 UNITY5.X GAME AI PROGRAMMING COOK BOOK 中提到的所有关于行为的派生类。我已经迫不及待的想要阅读了!
抵达 Arrive
distance: 到达目标的距离
targetRadius:目标抵达半径
slowRadius: 目标的缓冲半径
timeToTarget:不要被字面的意思误导,这里的time并非指时间,而是一个标量(Sclar) 不具有时间的意义,却可以控制抵达速度。
缓冲半径是如何运作的?
targetSpeed = agent.maxSpeed * distance / slowRadius;
首先运算缓冲半径的前提是目标已经抵达了缓冲半径,此时 distance <= slowRadius
。也就意味着 distance/slowRadius 越小。从而实现越接近目标速度成正比例下降。
实现追逐 ?
steering.linear = desiredVelocity - agent.velocity;
desiredVelocity为当前预估达到的速度(与方向) 减去 agent为目标物体朝向的速度(与方向),获得朝向目标的方向(与速度)
控制抵达的速度,防止超车
这里使用 if (steering.linear.magnitude > agent.maxAccel)
来规范化追逐者的速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| using UnityEngine; using System.Collections;
public class Arrive : AgentBehaviour { public float targetRadius; public float slowRadius; public float timeToTarget = 0.1f; public override Steering GetSteering() { Steering steering = new Steering(); Vector3 direction = target.transform.position - transform.position; float distance = direction.magnitude; float targetSpeed; if (distance < targetRadius) return steering; if (distance > slowRadius) targetSpeed = agent.maxSpeed; else targetSpeed = agent.maxSpeed * distance / slowRadius; Vector3 desiredVelocity = direction; desiredVelocity.Normalize(); desiredVelocity *= targetSpeed; steering.linear = desiredVelocity - agent.velocity; steering.linear /= timeToTarget; if (steering.linear.magnitude > agent.maxAccel) { steering.linear.Normalize(); steering.linear *= agent.maxAccel; } return steering; } }
|
Leave 离开
escapeRadius : 逃离半径(全速)
dangerRadius : 危险半径必须要逃离这个半径之外(变速)
timeToTarget : 不要被字面的意思误导,这里的time并非指时间,而是一个标量(Sclar) 不具有时间的意义,却可以控制离开速度。
实现变速逃离
reduce = distance / dangerRadius * agent.maxSpeed;
首先这段代码运作的前提是 distance <= dangerRadius
越接近想要逃离的物体,distance越小也就意味着最终的 reduce 也就越小。这显然不是我们要的最终效果,所以我们进行如下操作
我们做一下取反 float targetSpeed = agent.maxSpeed - reduce;
逻辑更正为 越接近想要逃离的物体,逃离速度越快
实现恒定速度逃离
escapeRadius < dangerRadius
我们最终的目的是离开危险区域。由(实现变速逃离)小节可知,当 reduce
为0的时候处于全速离开状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| using UnityEngine; using System.Collections;
public class Leave : AgentBehaviour { public float escapeRadius; public float dangerRadius; public float timeToTarget = 0.1f;
public override Steering GetSteering() { Steering steering = new Steering(); Vector3 direction = transform.position - target.transform.position; float distance = direction.magnitude; if (distance > dangerRadius) return steering; float reduce; if (distance < escapeRadius) reduce = 0f; else reduce = distance / dangerRadius * agent.maxSpeed; float targetSpeed = agent.maxSpeed - reduce; Vector3 desiredVelocity = direction; desiredVelocity.Normalize(); desiredVelocity *= targetSpeed; steering.linear = desiredVelocity - agent.velocity; steering.linear /= timeToTarget; if (steering.linear.magnitude > agent.maxAccel) { steering.linear.Normalize(); steering.linear *= agent.maxAccel; } return steering; } }
|
Facing objects 朝向物体
targetOrientation: 当前目标的弧度(0-360)
1 2 3 4 5 6 7 8 9 10 11 12
| public float MapToRange(float rotation) { rotation %= 360.0f; if (Mathf.Abs(rotation) > 180.0f) { if (rotation < 0.0f) rotation += 360.0f; else rotation -= 360.0f; } return rotation; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| using UnityEngine; using System.Collections;
public class Align : AgentBehaviour { public float targetRadius; public float slowRadius; public float timeToTarget = 0.1f;
public override Steering GetSteering() { Steering steering = new Steering(); float targetOrientation = target.GetComponent<Agent>().orientation; float rotation = targetOrientation - agent.orientation; rotation = MapToRange(rotation); float rotationSize = Mathf.Abs(rotation); if (rotationSize < targetRadius) return steering; float targetRotation; if (rotationSize > slowRadius) targetRotation = agent.maxRotation; else targetRotation = agent.maxRotation * rotationSize / slowRadius; targetRotation *= rotation / rotationSize; steering.angular = targetRotation - agent.rotation; steering.angular /= timeToTarget; float angularAccel = Mathf.Abs(steering.angular); if (angularAccel > agent.maxAngularAccel) { steering.angular /= angularAccel; steering.angular *= agent.maxAngularAccel; } return steering; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| using UnityEngine; using System.Collections;
public class Face : Align {
protected GameObject targetAux;
public override void Awake() { base.Awake(); targetAux = target; target = new GameObject(); target.AddComponent<Agent>(); }
public override Steering GetSteering() { Vector3 direction = targetAux.transform.position - transform.position; if (direction.magnitude > 0.0f) { float targetOrientation = Mathf.Atan2(direction.x, direction.z); targetOrientation *= Mathf.Rad2Deg; target.GetComponent<Agent>().orientation = targetOrientation; } return base.GetSteering(); }
void OnDestroy () { Destroy(target); } }
|