由三个简单的 转向行为组成,描述了个人如何基于其附近的群体的位置和速度进行动作:
分离separation:避免拥挤当地的群体
分离图
群组alignment:转向周围群体的平均航向
群组图
聚集cohesion:引导移动到周围同类的平均位置
聚集图
代码示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///<summary>
///群组行为
///<summary>
public class boids : MonoBehaviour
{
//public Transform target;
public float speed = 3;
public Vector3 velocity = Vector3.forward*2; //速度
public Vector3 startVelocity;
public float m = 1f; //质量
public Vector3 sumForce = Vector3.zero; //合力
public float separationDistance = 3f;//分离范围距离
public float separationWeirht = 1F; //分离权重
public List<GameObject> separationNeighors = new List<GameObject>();
public Vector3 separatoinForce = Vector3.zero;//分离的力
public float alignmentDistance = 6f; //队列距离
public float alignmentWeight = 1f; //队列权重
public List<GameObject> alignmentNeighbors = new List<GameObject>();
public Vector3 alignmentForce = Vector3.zero;//队列的力
public List<GameObject> cohesionNeighbors = new List<GameObject>();
public float cohesionWeight = 1f;
public Vector3 cohesionForce = Vector3.zero;//聚合的力
public float checkInterval = 0.2f; //调用间隔
private void Start()
{
startVelocity = velocity;
InvokeRepeating("CalcForce", 0, checkInterval);
}
void CalcForce()
{
//使力归零
sumForce = Vector3.zero;
separatoinForce = Vector3.zero;//分离的力
alignmentForce = Vector3.zero;//队列的力
cohesionForce = Vector3.zero;//聚合的力
separationNeighors.Clear(); //清空集合
Collider[] colliders = Physics.OverlapSphere(transform.position, separationDistance);
foreach(Collider c in colliders)
{
if(c!=null && c.gameObject!=this.gameObject) //c不为空且不为自身
{
separationNeighors.Add(c.gameObject);
}
}
//计算分离的力
foreach (GameObject neignbor in separationNeighors)
{
Vector3 dir = transform.position - neignbor.transform.position;
separatoinForce += dir.normalized / dir.magnitude;
}
if (separationNeighors.Count > 0)
{
separatoinForce *= separationWeirht;
sumForce += separatoinForce;
}
//计算队列的力
alignmentNeighbors.Clear();
colliders = Physics.OverlapSphere(transform.position, alignmentDistance);
foreach (Collider c in colliders)
{
if (c != null && c.gameObject != this.gameObject) //c不为空且不为自身
{
alignmentNeighbors.Add(c.gameObject);
}
}
Vector3 avgDir = Vector3.zero;
foreach (GameObject n in alignmentNeighbors)
{
avgDir += n.transform.forward;
}
if (alignmentNeighbors.Count > 0)
{
avgDir = avgDir / alignmentNeighbors.Count;
alignmentForce = avgDir - transform.forward;
alignmentForce *= alignmentWeight;
sumForce += alignmentForce;
}
//计算聚合的力
//若有分离力或者队伍为空则不施加聚合力
if ( alignmentNeighbors.Count>0)
{
Vector3 centor = Vector3.zero;
foreach (GameObject n in alignmentNeighbors)
{
centor += n.transform.position;
}
centor /= alignmentNeighbors.Count;
Vector3 dirToCenter = centor - transform.position; //自身到中心点向量
cohesionForce += dirToCenter;
cohesionForce *= cohesionWeight;
sumForce += cohesionForce;
//sumForce += alignmentForce;
}
//保持恒定飞行速度的力
Vector3 engineForce = startVelocity - velocity;
sumForce += engineForce;
//设定飞行目标的sumForce
//Vector3 targetDir = target.position - transform.position;
//sumForce = (targetDir.normalized - transform.forward) * speed;
}
private void Update()
{
Vector3 a = sumForce / m;
velocity += a * Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(velocity),Time.deltaTime); //绕运动方向旋转
transform.Translate(velocity * Time.deltaTime, Space.World);
// transform.Translate(transform.forward*Time.deltaTime, Space.World);
}
}