美文网首页
鱼群算法

鱼群算法

作者: Kyle_An | 来源:发表于2018-01-10 10:39 被阅读0次

群组行为是指多个对象组队同时行进的情况,我们可以坐下来,告诉每一个对象它该如何移动,但这样做的工作量太大。取而代之的是,我们去创建一个群组的领导,让它来为我们做这些,
这样我们所要做的就只是设置一些规则,然后群组中的boid就会自行组队。在本章中,我们将学习如何在unity3d中实现这种群组行为。
每个boid都可以应用一下三个基本的规则:
分离(seperation):群组中的每个个体都与相邻个体保持一定距离
列队(alignment):群组以相同速度,向相同方向移动
凝聚(cohesion):群组中心保持最小距离

在本节中我们将创建自己的场景,场景里会有一群对象,并使用C#实现群组行为。有两个主要的组成部分:每个boid行为,以及维持并领导整个群组的主要控制者。我们的场景层级如图,在一个名为UnityFlockController的控制器下面有一些boid实体----UnityFlock。每一个UnityFlock实体都是一个boid对象,它们会引用其父对象UnityFlockController实体作为它们的领导者。UnityFlockController将会在到达目标位置后,随机的更新下一个目标位置。UnityFlock是一个预制体,这个预制体仅仅是一个立方体网格,并拥有UnityFlock脚本。我们可以使用任何更有意思的其他的网格标识这个预制体,比如小鸟。

个体行为
boid是Craig Reynold创造的术语,用以表示类似小鸟这样的对象。我们将使用这个术语描述群组中的每个个体对象。UnityFlock这个脚本控制群组中每一个boid的行为。

using UnityEngine;  
using System.Collections;  
  
public class UnityFlock : MonoBehaviour {  
  
    public float minSpeed = 20;//最小移动速度  
    public float turnSpeed = 20;//旋转速度  
    public float randomFreq = 20;//用来确定更新randomPush变量的次数  
    public float randomForce = 20;//这个力产生出一个随机增长和降低的速度,并使得群组的移动看上去更加真实  
  
    //alignment variables列队变量  
    public float toOriginForce = 50;//用这个来保持所有boid在一个范围内,并与群组的原点保持一定距离  
    public float toOriginRange = 100;//群组扩展的程度  
  
    public float gravity = 2;  
  
    //seperation variables分离变量  
    public float avoidanceRadius = 50;  
    public float avoidanceForce = 20;//这两个变量可以让每个boid个体之间保持最小距离  
  
    //cohesion variables凝聚变量,这两个变量可用来与群组的领导者或群组的原点保持最小距离。  
    public float followVelocity = 4;  
    public float followRadius = 40;  
  
    //这些变量控制了boid的移动  
    private Transform origin;//设为父对象,以控制整个群组中的对象。  
    private Vector3 velocity;  
    private Vector3 normalizeedVelocity;  
    private Vector3 randomPush;//更新基于randomFore的值  
    private Vector3 originPush;  
    //以下两个变量存储相邻boid的信息,当前boid需要知道群组中其他boid的信息  
    private Transform[] objects;  
    private UnityFlock[] otherFlocks;  
    private Transform transformComponent;  
  
    /* 
     
         */  
  
    void Start () {  
        randomFreq = 1.0f / randomFreq;  
  
        //将父类指定为origin  
        origin = transform.parent;  
  
        //Flock transform  
        transformComponent = transform;  
  
        //Temporary components临时  
        Component[] tempFlocks = null;  
  
        //Get all the unity flock omponents from the parent transform in the group  
        if (transform.parent )  
        {  
            tempFlocks = transform.parent.GetComponentsInChildren<UnityFlock>();  
        }  
  
        //Assign and store all the flock objects in this group  
        objects = new Transform[tempFlocks.Length];  
        otherFlocks = new UnityFlock[tempFlocks.Length];  
        for (int i = 0; i < tempFlocks.Length; i++)  
        {  
            objects[i] = tempFlocks[i].transform;  
            otherFlocks[i] = (UnityFlock)tempFlocks[i];  
        }  
  
        //Null Parent as the flok leader will be UnityFlockController object  
        transform.parent = null;  
  
        //Calculate random push depends on the random frequency provided  
        StartCoroutine(UpdateRandom());  
    }  
  
    IEnumerator UpdateRandom()  
    {  
        while (true)  
        {  
            randomPush = Random.insideUnitSphere * randomForce;  
            yield return new WaitForSeconds(randomFreq + Random.Range(-randomFreq / 2.0f, randomFreq / 2.0f));  
        }  
    }  
  
    void Update () {  
        //internal variables  
        float speed = velocity.magnitude;//获取速度大小  
        Vector3 avgVelocity = Vector3.zero;  
        Vector3 avgPosition = Vector3.zero;  
        float count = 0;  
        float f = 0.0f;  
        float d = 0.0f;  
        Vector3 myPosition = transformComponent.position;  
        Vector3 forceV;  
        Vector3 toAvg;  
        Vector3 wantedVel;  
        for (int i = 0; i < objects.Length; i++)  
        {  
            Transform transform = objects[i];  
            if (transform != transformComponent)  
            {  
                Vector3 otherPosition = transform.position;  
                //Average position to calculate cohesion  
                avgPosition += otherPosition;  
                count++;  
                //Directional vector from other flock to this flock  
                forceV = myPosition - otherPosition;  
                //Magnitude of that diretional vector(length)  
                d = forceV.magnitude;  
                //Add push value if the magnitude,the length of the vetor,is less than followRadius to the leader  
                if (d < followRadius)  
                {  
                    //calculate the velocity,the speed of the object,based current magnitude is less than the specified avoidance radius  
                    if (d < avoidanceRadius)  
                    {  
                        f = 1.0f - (d / avoidanceRadius);  
                        if (d > 0)  
                        {  
                            avgVelocity += (forceV / d) * f * avoidanceForce;  
                        }  
                    }  
                    //just keep the current distance with the leader  
                    f = d / followRadius;  
                    UnityFlock otherSealgull = otherFlocks[i];  
                    //we normalize the otherSealgull veloity vector to get the direction of movement,then wo set a new veloity  
                    avgVelocity += otherSealgull.normalizeedVelocity * f * followVelocity;  
                }  
            }  
        }  
        //上述代码实现了分离规则,首先,检查当前boid与其他boid之间的距离,并相应的更新速度,接下来,用当前速度除以群组中的boid的数目,计算出群组的平均速度  
  
        if (count > 0)  
        {  
            //Calculate the aveage flock veloity(Alignment)  
            avgVelocity /= count;  
            //Calculate Center value of the flock(Cohesion)  
            toAvg = (avgPosition / count) - myPosition;  
        }  
        else  
        {  
            toAvg = Vector3.zero;  
        }  
        //Directional Vector to the leader  
        forceV = origin.position - myPosition;  
        d = forceV.magnitude;  
        f = d / toOriginRange;  
        //Calculate the velocity of the flok to the leader  
        if (d > 0)  
        {  
            originPush = (forceV / d) * f * toOriginForce;  
        }  
  
        if (speed < minSpeed && speed > 0)  
        {  
            velocity = (velocity / speed) * minSpeed;  
        }  
  
        wantedVel = velocity;  
        //Calculate final velocity  
        wantedVel -= wantedVel * Time.deltaTime;  
        wantedVel += randomPush * Time.deltaTime;  
        wantedVel += originPush * Time.deltaTime;  
        wantedVel += avgVelocity * Time.deltaTime;  
        wantedVel += toAvg.normalized * gravity * Time.deltaTime;  
        //Final Velocity to rotate the flock into  
        velocity = Vector3.RotateTowards(velocity, wantedVel, turnSpeed * Time.deltaTime, 100.0f);  
  
        transformComponent.rotation = Quaternion.LookRotation(velocity);  
  
        transformComponent.Translate(velocity * Time.deltaTime, Space.World);  
  
        normalizeedVelocity = velocity.normalized;  
    }  
}  

相关文章

  • 鱼群算法

    群组行为是指多个对象组队同时行进的情况,我们可以坐下来,告诉每一个对象它该如何移动,但这样做的工作量太大。取而代之...

  • 鱼群AI群聚算法

    通过模拟鱼群或是雁群的群聚AI算法主要的有三种行为分别是分散,对齐,凝聚即当鱼群之间距离靠的过近时它们会主动散开,...

  • 人工鱼群算法超详细解析附带JAVA代码

    01 前言 本着学习的心态,还是想把这个算法写一写,给大家科普一下的吧。 02 人工鱼群算法 2.1 定义 人工鱼...

  • 鱼群

    受上一张海豹画风影响,还是想将小人鱼被鱼群包围的画面的色彩靓丽一些,完了感觉稍稍有些俗气。先不改了,嘿嘿。完成稿如...

  • 鱼群

    斯诺端着高脚杯,轻松写意地倚在湖边地木制围栏上。傍晚的斜阳倒映在湖面的涟漪,泛起粼粼的波光。湖边的小屋沐浴在森林的...

  • 粒子群(PSO)算法笔记

    一、简介 1.什么是粒子群算法? 粒子群算法模仿昆虫、兽群、鸟群和鱼群等的群集行为,这些群体按照一种合作的方式寻找...

  • 鱼群里

  • 守着鱼群

    从浪花破碎里走来 我到峭壁的锋利里去 谁不在半夜痛哭 又在清晨微笑 一半生命 我留给陆地 另一半给太阳 我是让开粮...

  • 鱼群颂

    全体毕业生:也许这是一首关于爱的颂歌,歌唱者是你是我。 黄鱼:毕业那天,我看到了那顶被我戴在头上的皇冠,也许从摘下...

  • 鱼群,蜂群?!

    20171122 刚刚听了一段关于AI的TED演讲(晚上听TED应该不错),其中讲到鱼群对人工智能的启发:没有领导...

网友评论

      本文标题:鱼群算法

      本文链接:https://www.haomeiwen.com/subject/tuonnxtx.html