Unity游戏开发中的人工智能编程

unity3d AI 学习--群组行为

https://blog.csdn.net/qq_28221881/article/details/52856757

Unity群组行为

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;

    /// <summary>
    /// 开始速度
    /// </summary>
    private Vector3 startVelocity;
    /// <summary>
    /// 当前的速度
    /// </summary>
    public Vector3 velocity = Vector3.forward;



    /// <summary>
    /// 质量
    /// </summary>
    public float m = 3;

    /// <summary>
    /// 距离我们三米内的乌鸦 就会跟其他乌鸦进行分离
    /// </summary>
    [Header("距离我们三米内的乌鸦 就会跟其他乌鸦进行分离")]
    public float separationDistance = 2;

    [Header("要添加的 3米附近的乌鸦集合 ")]
    public List<GameObject> seaprationNeighbors = new List<GameObject>();

    


    /// <summary>
    /// 权重的力
    /// </summary>
    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<GameObject> alignmentNeighbors = new List<GameObject>();

    [Header("队列的力")]
    public Vector3 alignmentForce = Vector3.zero;


    /// <summary>
    /// 聚集的力的全中
    /// </summary>
    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<Animation>();
        //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);


    }
}

猜你喜欢

转载自blog.csdn.net/qq_35422344/article/details/86518122