鱼群算法

群组行为是指多个对象组队同时行进的情况,我们可以坐下来,告诉每一个对象它该如何移动,但这样做的工作量太大。取而代之的是,我们去创建一个群组的领导,让它来为我们做这些,
这样我们所要做的就只是设置一些规则,然后群组中的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;  
    }  
}  
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Saying “ 亲爱的她蜜,《南山南》,张磊在好声音的舞台上唱《南山南》,这个声音让你觉得有故事,打动你。他安安...
    她生活阅读 1,119评论 0 2
  • 亲情,本是一段割舍不断的血脉,是手足相连的情谊。但在渐渐长大的时光里,不经意便慢慢疏离,划分了距离。 遥想童年的记...
    白水概会阅读 282评论 0 1
  • 我除了自己,不想成为其他任何人。她之前很害怕一片树林,但硬着头皮坐过去之后,发现也没什么,所以很多事情,真正去做了...
    大头猪阅读 240评论 0 0
  • (读书群的一个朋友强行摊派任务,要求每一个成员必须完成一篇高考作文,题目自选。虽然被摊派的感觉很痛苦,没办法,勉为...
    考拉浅浅笑阅读 337评论 0 1