上一篇我们讲到关于 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);
}
}