一:效果演示
不使用群组算法和使用群组算法的演示视频
二:什么是群组行为
群组行为属于人工智能思想,比如说人群走路、鸟群飞行、鱼群游动,群组中成员之间不应该很规律的运动,例如不能拥挤到一起,而是更加真实的去模拟现实中的场景
下面是不使用群组行为和使用群组行为的演示
群组中的三种行为:
——分隔:成员间保持一定距离,不能太近
——队列:群组以相同的速度向相同方向运动
——聚集:避免与临近成员距离太远
三:群组行为中的三种行为
为了更好的模拟现实环境,使用施加力的方式替代直接修改物体速度,因为直接修改物体的速度会无视各种外力,而施加力是一种仿物理的方式
——分隔
当成员之间相距很近时,给其一个相反的力进行分离
——队列
当与大部队运动方向不一致时,给其一个力进行调整
——聚集
当与其他成员相距很远时,就选取就近几个成员的中心点,施加力实现聚集
四:代码实现
using UnityEngine;
/// <summary>
/// 群组行为中的个体
/// </summary>
public class UnityFlock : MonoBehaviour
{
public Transform target;//目标物体
[Header("运动速度")]
public float speed;
[Header("物体质量")]
private int m = 1;
[Header("需要分离的距离")]
[Header("====================")]
public float separationDist;
[Header("分离力的比重")]
public float separationWeight;
[Header("需要队列的距离")]
public float alignmentDist;
[Header("队列力的比重")]
public float alignmentWeight;
[Header("需要聚集的距离")]
public float cohesionDist;
[Header("聚集力的比重")]
public float cohesionWeight;
private Vector3 velocity;//速度
private void Awake()
{
velocity = Vector3.forward;
}
private void Update()
{
Vector3 sumForce = Vector3.zero;
sumForce += Separation() * separationWeight;
sumForce += Alignment() * alignmentWeight;
sumForce += Cohesion() * cohesionWeight;
sumForce += Seek() * speed;
Vector3 a = sumForce / m;
velocity += a * Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(velocity), 0.2f);
transform.Translate(transform.forward * Time.deltaTime, Space.World);
}
/// <summary>
/// 寻找目标
/// </summary>
/// <returns></returns>
private Vector3 Seek()
{
Vector3 force = Vector3.zero;
Vector3 dir = target.position - transform.position;
force = dir.normalized - transform.forward;
return force;
}
/// <summary>
/// 得到分离的力
/// </summary>
private Vector3 Separation()
{
Vector3 separationForce = Vector3.zero;
GameObject[] objs = GameObject.FindGameObjectsWithTag("UnityFlock");
foreach (var unity in objs)
{
if (unity == gameObject)
{
continue;
}
if (Vector3.Distance(transform.position, unity.transform.position) <= separationDist)
{
Vector3 dir = transform.position - unity.transform.position;
separationForce += dir.normalized / dir.magnitude;
}
}
return separationForce;
}
/// <summary>
/// 得到队列的力
/// </summary>
private Vector3 Alignment()
{
Vector3 alignmentForce = Vector3.zero;
GameObject[] objs = GameObject.FindGameObjectsWithTag("UnityFlock");
Vector3 avgDir = Vector3.zero;
int counter = 0;
foreach (var unity in objs)
{
if (unity == gameObject)
{
continue;
}
if (Vector3.Distance(transform.position, unity.transform.position) < alignmentDist)
{
counter++;
avgDir += unity.transform.forward;
}
}
avgDir /= counter;
alignmentForce += (avgDir - transform.forward).normalized;
return alignmentForce;
}
/// <summary>
/// 聚集
/// </summary>
private Vector3 Cohesion()
{
Vector3 cohesionForce = Vector3.zero;
GameObject[] objs = GameObject.FindGameObjectsWithTag("UnityFlock");
Vector3 avgDir = Vector3.zero;
int counter = 0;
foreach (var unity in objs)
{
if (unity == gameObject)
{
continue;
}
if (Vector3.Distance(transform.position, unity.transform.position) < alignmentDist)
{
counter++;
avgDir += unity.transform.position;
}
}
avgDir /= counter;
cohesionForce += (avgDir - transform.position).normalized;
return cohesionForce;
}
}