群组行为(群集行为)与视觉的实现

实现群组行为需要三个力:分离力,队列力,聚集力

群组行为(群集行为)与视觉的实现_第1张图片
image.png

资料: http://www.red3d.com/cwr/boids/
根据牛顿第二定律可算出加速度: A(加速度)=F(力)/M(质量)这里的力就是前面三个力的合力.
下面我们用代码实现

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CrowAI : MonoBehaviour
{
    public float speed = 3;
    public Vector3 velocity = Vector3.forward;//当前速度
    private Vector3 startVelocity;

    public Transform target;

    public Vector3 sumForce = Vector3.zero;//和力
    public float m = 1;//质量


    public float separationDistance = 3;
    public List separationNeighbors = new List();//在separationDistance半径内的所有物体
    public float separationWeight = 1;
    public Vector3 separationForce = Vector3.zero;//分离的力

    public float alignmentDistance = 6;
    public Vector3 alignmentForce = Vector3.zero;//队列的力
    public float alignmentWeight = 1;
    public List alignmentNeighbors = new List();

    public Vector3 cohesionForce = Vector3.zero;//聚集的力
    public float cohesionWeight = 1;

    public float checkInterval = 0.2f;//多久计算一次合力


    public float animRandowTime = 2f;
    private Animation ani;

    private void  Start()
    {
        target = GameObject.Find("Target").transform;
        startVelocity = velocity;

        InvokeRepeating("CalcForce", 0, checkInterval);
        ani = GetComponentInChildren();
        Invoke("playAnim", Random.Range(0, animRandowTime));
    }

    void playAnim()
    {
        ani.Play();
    }
    //计算合力
    void CalcForce()
    {
         sumForce = Vector3.zero;

         separationForce = Vector3.zero;//分离的力
         alignmentForce = Vector3.zero;//队列的力
         cohesionForce = Vector3.zero;//聚集的力
        separationNeighbors.Clear();
        //返回一个Collider数组,以transform.position为中心以separationDistance为半径发射一个球体, 其中所有碰撞到球体都包含在这个数组中(包含它自己)。
        Collider[] colliders = Physics.OverlapSphere(transform.position, separationDistance);
        foreach (Collider c in colliders)
        {
            if (c != null && c.gameObject != this.gameObject)
            {
                separationNeighbors.Add(c.gameObject);
            }
        }
        //计算分离的力
        foreach (GameObject neighbor in separationNeighbors)
        {
            Vector3 dir = transform.position - neighbor.transform.position;
            separationForce += dir.normalized.normalized/dir.magnitude;
        }
        if (separationNeighbors.Count > 0)
        {
            separationForce *= separationWeight;
            sumForce += separationForce;
        }
        //计算队列的力
        alignmentNeighbors.Clear();
        colliders = Physics.OverlapSphere(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)
        {
            avgDir /= alignmentNeighbors.Count;
            alignmentForce = avgDir - transform.forward;
            alignmentForce *= alignmentWeight;
            sumForce += alignmentForce;
        }
        //聚集的力
        if ( alignmentNeighbors.Count > 0)
        {
            Vector3 center = Vector3.zero;

            foreach (GameObject n in alignmentNeighbors)
            {
                center += n.transform.position;
            }
            center /= alignmentNeighbors.Count;
            Vector3 dirToCenter = center - transform.position;
            cohesionForce += dirToCenter;
            cohesionForce *= cohesionWeight;
            sumForce += cohesionForce;
        }


        //保持恒定飞行速度的力
        Vector3 engineForce = velocity.normalized * startVelocity.magnitude;
        sumForce += engineForce * 0.1f;

        Vector3 targetDir = target.position - transform.position;
        sumForce += (targetDir.normalized - transform.forward) * speed;
    }
    private void Update()
    {  //A(加速度)=F(力)/M(质量)
        Vector3 a = sumForce / m;
        velocity += a * Time.deltaTime;

        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(velocity), Time.deltaTime * 3);


        transform.Translate(transform.forward * Time.deltaTime * velocity.magnitude, Space.World);

    }
}

这样鸟群飞起来比较凌乱,就有了AI鸟群的感觉.


群组行为(群集行为)与视觉的实现_第2张图片
image.png

群组行为(群集行为)与视觉的实现_第3张图片
image.png
视觉感知
public class Soldier : MonoBehaviour {
    public float ViewDistance = 5;
    public float ViewAngle=120;
    private Transform PlyerTrans;
    void Start () {
        PlyerTrans = GameObject.Find("Player").transform;
    }
    

    void Update () {
        if (Vector3.Distance(transform.position, PlyerTrans.position) <= ViewDistance)
        {
            //取得方向
            Vector3 playerDir = PlyerTrans.position - transform.position;
            //取得两个向量夹角
            float angle=Vector3.Angle(playerDir,transform.forward);
            if (angle <= ViewAngle/2)
            {
                Debug.Log("在视野范围内");
            }
        }
    }
}

你可能感兴趣的:(群组行为(群集行为)与视觉的实现)