ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Unity鱼群算法

2020-06-13 19:05:24  阅读:1140  来源: 互联网

标签:Vector3 myGroup float Unity transform 鱼群 算法 public dir


一:前言

鱼群算法又称为群组行为,比如说走路,但是不能很规律的执行走路,要有人工智能的感觉的去执行走路,更加真实的去模拟现实,并且人与人之间不能拥挤到一起。常用与鸟群,鱼群,人群等

鱼群算法的规则:
——分隔规则: 尽量避免与临近成员过于拥挤
——对准规则: 尽量与临近成员的平均方向一致
——内聚规则: 尽量朝临近成员的中心移动


二:效果演示


三:代码

——组的总控制器

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// 组的总控制器(挂载到组长身上,可以是玩家也可以是要跟随的物体)
/// </summary>
public class GroupController : MonoBehaviour
{
    private static List<GroupController> groups;//所有组

    [Header("组中成员的层")]
    public LayerMask mask;
    [Header("组中成员的ID")]
    public int groupID = 0;
    [Header("组中成员始终保持的距离")]
    public float keepDis;
    [Header("组中成员始终保持的距离的权重")]
    public float keepWeight;
    [Header("多少距离算离得太近")]
    public float targetCloseDistance;
    [Header("组中成员停止移动的距离")]
    public float stopDis;

    /// <summary>
    /// 得到成员属于哪个组
    /// </summary>
    /// <param name="index">成员ID</param>
    /// <returns></returns>
    public static GroupController GetGroup(int index)
    {
        if (groups == null)
        {
            groups = new List<GroupController>(FindObjectsOfType(typeof(GroupController)) as GroupController[]);
        }

        for (int i = 0; i < groups.Count; i++)
        {
            if (groups[i].groupID == index)
            {
                return groups[i];
            }
        }
        throw new System.Exception("没有找到相同ID的组");
    }
}

 

 


——控制组中的每个成员自身

using UnityEngine;

/// <summary>
/// 挂载到组中的每个成员身上
/// </summary>
public class GroupMember : MonoBehaviour
{
    private GroupController myGroup;//当前成员的GroupController组件

    //速度和移动相关参数
    private float targetSpeed;
    private float speed;
    private float currentSpeed;
    private Vector3 myMovement;

    [Header("属于的组ID")]
    public int groupId;
    [Header("移动速度")]
    public float moveSpeed;
    [Header("旋转速度")]
    public float rotateSpeed;

    private void Start()
    {
        myGroup = GroupController.GetGroup(groupId);
    }

    void Update()
    {
        Vector3 dis = myGroup.transform.position - transform.position;
        Vector3 dir = dis.normalized;

        //重新计算目的地距离权重
        if (dis.magnitude < myGroup.targetCloseDistance)
        {
            dir *= dis.magnitude / myGroup.targetCloseDistance;
        }
        dir += GetAroundMemberInfo();//获取周围组的移动

        //计算移动速度
        if ((myGroup.transform.position - transform.position).magnitude < myGroup.stopDis)
        {
            targetSpeed = 0;
        }
        else
        {
            targetSpeed = moveSpeed;
        }
        speed = Mathf.Lerp(speed, targetSpeed, 2 * Time.deltaTime);

        //————————————————————移动
        transform.right = -dir;
        Move(dir, speed);
    }

    /// <summary>
    /// 得到周围成员的信息
    /// </summary>
    /// <returns></returns>
    private Vector3 GetAroundMemberInfo()
    {
        Collider2D[] c = Physics2D.OverlapCircleAll(transform.position, myGroup.keepDis, myGroup.mask);//获取周围成员
        Vector3 dis;
        Vector3 v1 = Vector3.zero;
        Vector3 v2 = Vector3.zero;
        for (int i = 0; i < c.Length; i++)
        {
            GroupMember otherMember = c[i].GetComponent<GroupMember>();
            dis = transform.position - otherMember.transform.position;//距离
            v1 += dis.normalized * (1 - dis.magnitude / myGroup.keepDis);//查看与周围成员的距离
            v2 += otherMember.myMovement;//查看周围成员移动方向

            Debug.DrawLine(transform.position, otherMember.transform.position, Color.yellow);
        }
        return v1.normalized * myGroup.keepWeight + v2.normalized;//添加权重因素
    }

    /// <summary>
    /// 移动
    /// </summary>
    /// <param name="_dir">方向</param>
    /// <param name="_speed">速度</param>
    private void Move(Vector3 _dir, float _speed)
    {
        Vector3 finialDirection = _dir.normalized;
        float finialSpeed = _speed, finialRotate = 0;
        float rotateDir = Vector3.Dot(finialDirection, transform.right);
        float forwardDir = Vector3.Dot(finialDirection, transform.forward);

        if (forwardDir < 0)
        {
            rotateDir = Mathf.Sign(rotateDir);
        }
        if (forwardDir < -0.2f)
        {
            finialSpeed = Mathf.Lerp(currentSpeed, -_speed * 8, 4 * Time.deltaTime);
        }

        //——————————防抖
        if (forwardDir < 0.98f)
        {
            finialRotate = Mathf.Clamp(rotateDir * 180, -rotateSpeed, rotateSpeed);
        }

        finialSpeed *= Mathf.Clamp01(_dir.magnitude);
        finialSpeed *= Mathf.Clamp01(1 - Mathf.Abs(rotateDir) * 0.8f);

        transform.Translate(Vector3.left * finialSpeed * Time.deltaTime);
        transform.Rotate(Vector3.forward * finialRotate * Time.deltaTime);

        currentSpeed = finialSpeed;
        myMovement = _dir * finialSpeed;
    }

}

 

标签:Vector3,myGroup,float,Unity,transform,鱼群,算法,public,dir
来源: https://blog.csdn.net/LLLLL__/article/details/106713870

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有