https://blog.csdn.net/qq_28221881/article/details/52856757
https://blog.csdn.net/qq_38186269/article/details/81486139
具体的分离 队列 聚合力的大小参数根据实际情况修改
飞往目标点
到达目标点后
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrowAI : MonoBehaviour
{
public Transform targetTranform;
public float speed = 3;
///
/// 开始速度
///
private Vector3 startVelocity;
///
/// 当前的速度
///
public Vector3 velocity = Vector3.forward;
///
/// 质量
///
public float m = 3;
///
/// 距离我们三米内的乌鸦 就会跟其他乌鸦进行分离
///
[Header("距离我们三米内的乌鸦 就会跟其他乌鸦进行分离")]
public float separationDistance = 2;
[Header("要添加的 3米附近的乌鸦集合 ")]
public List seaprationNeighbors = new List();
///
/// 权重的力
///
public float separationWeight = 1;
[Header("综合的力")]
public Vector3 sumForce = Vector3.zero;
[Header("分离的力")]
public Vector3 separationForce = Vector3.zero;
[Header(" 队列 的距离 ")]
public float alignmentDistance = 6;
[Header(" 队列 的力的全中 ")]
public float alignmentWeight = 1;
[Header("队列的集合")]
public List alignmentNeighbors = new List();
[Header("队列的力")]
public Vector3 alignmentForce = Vector3.zero;
///
/// 聚集的力的全中
///
public float conhesionWeight = 1;
[Header("聚集的力")]
public Vector3 cohesionForce = Vector3.zero;
[Header("检查的时间间隔")]
public float chechInterval = 0.2f; //若在Update中调用,比较耗费性能
public float animRandom = 2f;
public Animation animatio;
private void Start()
{
targetTranform = GameObject.Find("Target").transform;
//使乌鸦的运动速度保持不变
startVelocity = velocity;
InvokeRepeating("CalcForce", 0, chechInterval);
// targetTranform = GameObject.Find("TargetPos").transform;
animatio = GetComponentInChildren();
//yield return new WaitForSeconds(UnityEngine. Random.Range(0, animRandom));
Invoke("PlayAnim", Random.Range(0, animRandom));
}
void PlayAnim() {
animatio.Play();
}
void CalcForce()
{
//每次计算 把力归零
sumForce = Vector3.zero;
separationForce = Vector3.zero;
alignmentForce = Vector3.zero;
cohesionForce = Vector3.zero;
seaprationNeighbors.Clear();
//Physics.OverlapSphere (物体位置,半径) 检测球范围内内有多少物体(包含自身) 返回一个Collide集合
Collider[] colliders = Physics.OverlapSphere(this.transform.position, separationDistance);
//将Collide添加到集合中
foreach (Collider item in colliders)
{
if (item != null && item.gameObject != this.gameObject)
{
seaprationNeighbors.Add(item.gameObject);
}
}
//分离的力
foreach (GameObject neighbor in seaprationNeighbors)
{
Vector3 dir = transform.position - neighbor.transform.position;//得到分离的方向 相反的方向,远离
separationForce += dir.normalized / dir.magnitude; // dir(得到方向向量) / dir的长度(自己到neighbor的距离)
//dir的长度 越小 得到的 力就越大 长度越大产生的力就越小
}
//旁边有乌鸦才会更新
if (seaprationNeighbors.Count>0)
{
//现在 separationWeight 的力为1 没有影响 如果发现separationWeight 比较小 就刷一个全中 让他变大
separationForce *= separationWeight;
sumForce += separationForce;
}
//队列的力
alignmentNeighbors.Clear();
colliders = Physics.OverlapSphere(this.transform.position, alignmentDistance);
foreach (Collider c in colliders)
{
if (c!=null && c.gameObject!=this.gameObject)
{
alignmentNeighbors.Add(c.gameObject);
}
}
//平均朝向
Vector3 avgDir = Vector3.zero;
foreach (GameObject n in alignmentNeighbors)
{
//总的朝向
avgDir += n.transform.forward;
}
if (alignmentNeighbors.Count > 0)
{
//除以总数等于 平均朝向 即为 want方向
avgDir /= alignmentNeighbors.Count;
//根据 平均方向 - 当前方向 就等于 要朝向的 朝向 即temp方向
alignmentForce = avgDir - transform.forward;//越靠近,temp向量越小,力越小
//刷个权重 如果力太小的话可以放大
alignmentForce *= alignmentWeight;
sumForce += alignmentForce;
}
//聚集的力
//seaprationNeighbors 分离的数组大于0 只有小于等于0的时候 才能聚集
//alignmentNeighbors 队列的力小于等于0 都没办法计算 队列的力了
if (alignmentNeighbors.Count > 0) {
//中心点
Vector3 center = Vector3.zero;
foreach (GameObject item in alignmentNeighbors)
{
center += item.transform.position;
}
center /= alignmentNeighbors.Count;
//得到移动的力 center 越大 得到的力就越大 刚好符合
Vector3 dirToCenter = center - this.transform.position;
cohesionForce += dirToCenter;
// 如果上面的力不行的话就是用这种方法
// cohesionForce += dirToCenter .normalized *velocity.magnitude;
cohesionForce *= conhesionWeight;
sumForce += cohesionForce;
}
////
////保持恒定飞行速度向前飞
// Vector3 engineForce = startVelocity - velocity;
////Vector3 engineForce = velocity.normalized * startVector3.magnitude;
//sumForce += engineForce * 0.1f;
//向某个物体飞去
Vector3 targetDir = targetTranform.position - transform.position;
//temp方向减去 当前方向
sumForce += (targetDir.normalized - transform.forward) * speed;
}
// Update is called once per frame
void Update()
{
//加速度
Vector3 a = sumForce / m;
velocity += a * Time.deltaTime;
//因为 初始的队列的方向是一致的 就会导致 队列的力不起作用 所以必须加上下面的代码
//当前的朝向 和速度的朝向保持一致
//transform.rotation = Quaternion.LookRotation(velocity);
//加入插值,不会突然变向
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(velocity), Time.deltaTime);
//transform.Translate(velocity * Time.deltaTime, Space.World);
transform.Translate(transform.forward * Time.deltaTime *velocity.magnitude, Space.World);
}
}