首页 > 代码库 > 游戏AI之群组行为

游戏AI之群组行为

群组行为指的是多个对象组队同时进行的情况。每个boid需满足分离,队列,凝聚三个基本的规则。

分离:群组中的每个个体都与相邻的个体保持一定的距离。

队列:群组以相同的速度,向相同的方向移动。

凝聚:与群组的中心保持最小距离。

参见:http://www.red3d.com/cwr/boids/

结构:

控制器:即头鸟下有controller类来控制自身的移动。

个体成员:单独的个体,通过引用控制器的位置信息来产生群组跟随的效果。

技术分享

群组中的个体:

  1 using UnityEngine;  2 using System.Collections;  3   4   5 /// <summary>  6 /// 该类是对群体中的每个个体行为的约束,即单个的鸟  7 /// </summary>  8 public class UnityFlock : MonoBehaviour  9 { 10  11     //最小速度,转向速度,随机频率,随机力 12     public float minSpeed = 20.0f; 13     public float turnSpeed = 20.0f; 14     public float randomFreq = 20.0f; 15     public float randomForce = 20.0f; 16  17     //队列属性 :向心力,向心区间,吸引力 18     public float toOriginForce = 50.0f; 19     public float toOriginRange = 100.0f; 20  21     public float gravity = 2.0f; 22  23     //分离属性:规避力,规避半径 24     public float avoidanceForce = 20.0f; 25     public float avoidanceRadius = 50.0f; 26      27     //凝聚属性:追随速度,追随半径(相对于领导者即头鸟) 28     public float followVelocity = 4.0f; 29     public float followRadius = 40.0f; 30  31  32     //控制单个个体运动的属性:父对象即头鸟,速度,归一化速度,随机推力,父对象的推力。。。 33     private Transform origin; 34     private Vector3 velocity; 35     private Vector3 normalizedVelicity; 36     private Vector3 randomPush; 37     private Vector3 originPush; 38     private Transform[] objects; 39     private UnityFlock[] otherFlocks;//其他个体集合 40     private Transform transformCompont; 41  42  43  44     // Use this for initialization 45     void Start () 46     { 47         randomFreq = 1.0f/randomFreq;//获取随机变化的频率 48         //设置父节点为origin 49         origin = transform.parent; 50  51         transformCompont = transform; 52  53         //临时组件数组 54         Component[] tempFlocks = null; 55  56         if (transform.parent) 57         { 58             tempFlocks = transform.parent.GetComponentsInChildren<UnityFlock>(); 59         } 60  61         objects=new Transform[tempFlocks.Length]; 62         otherFlocks=new UnityFlock[tempFlocks.Length]; 63  64         //将群体的位置信息和群体加载到数组 65         for (int i = 0; i < tempFlocks.Length; i++) 66         { 67             objects[i] = tempFlocks[i].transform; 68             otherFlocks[i] = (UnityFlock)tempFlocks[i]; 69         } 70  71         transform.parent = null; 72  73         StartCoroutine(UpdateRandom()); 74     } 75  76     //基于randomFreq的频率来更新randompush的频率 77     IEnumerator UpdateRandom() 78     { 79         while (true) 80         { 81             randomPush = Random.insideUnitSphere*randomForce;//Random.insideUnitSphere随机返回单位球体类一点坐标,配合随机力度来跟新randomPush 82             yield return new WaitForSeconds(randomFreq+Random.Range(-randomFreq/2,randomFreq/2));//依据随机频率在一定时间分为类变换randomPush 83         } 84     } 85  86     // Update is called once per frame 87     void Update () 88     { 89         float speed = velocity.magnitude; 90         Vector3 avgVelocity = Vector3.zero; 91         Vector3 avgPosition = Vector3.zero; 92         float count = 0; 93         float f = 0.0f; 94         float d = 0.0f; 95         Vector3 myPosition = transformCompont.position; 96         Vector3 forceV; 97         Vector3 toAvg; 98         Vector3 wantedVel; 99 100         for (int i = 0; i < objects.Length; i++)101         {102             Transform transform = objects[i];103             if (transform != transformCompont)104             {105                 Vector3 otherPositon = transform.position;106 107                 //平均位置来计算聚合108                 avgPosition += otherPositon;109                 count++;110 111                 //从其他群体到这个的向量112                 forceV = myPosition - otherPositon;113 114                 //上面向量的长度115                 d = forceV.magnitude;116 117                 //如果向量长度比规避半径小的话,则加大推力118                 if (d < followRadius)119                 {120                     //如果当前的向量长度小于规定的逃离半径的话,则基于 逃离半径计算对象的速度121                     if (d > 0)122                     {123                          f = 1.0f - (d/avoidanceRadius);124                         avgVelocity += (forceV / d) * f * avoidanceForce;125                         //向量除以它的模得到自己的单位向量126                     }127 128                 }129 130                 //保持与头儿的距离131                 f = d/followRadius;132                 UnityFlock otherSealgull = otherFlocks[i];133 134                 //标准化otherSealgul的速度来获取移动的方向,接下来设置一个新的速度135                 avgVelocity += otherSealgull.normalizedVelicity * f *followVelocity;136 137             }138         }139 140         if (count > 0)141         {142             //得到平均速度143             avgVelocity /= count;144             //获得平均位置与对象间的向量145             toAvg = (avgPosition/count) - myPosition;146         }147         else148         {149             toAvg = Vector3.zero;150         }151 152         //153         forceV = origin.position - myPosition;154         d = forceV.magnitude;155         f = d/toOriginRange;156         //157         if (d > 0)158             originPush = (forceV/d)*f*toOriginForce;159         if (speed < minSpeed && speed > 0)160             velocity = (velocity/speed)*minSpeed;161 162         wantedVel = velocity;163 164         //最终速度165         wantedVel -= wantedVel*Time.deltaTime;166         wantedVel += randomPush*Time.deltaTime;167         wantedVel += originPush*Time.deltaTime;168         wantedVel += avgVelocity*Time.deltaTime;169         wantedVel += toAvg.normalized*gravity*Time.deltaTime;170 171         //调整速度使之转向最终速度172         velocity = Vector3.RotateTowards(velocity, wantedVel,turnSpeed*Time.deltaTime, 100.00f);173 174         transformCompont.rotation = Quaternion.LookRotation(velocity);175 176         //移动对象177         transformCompont.Translate(velocity*Time.deltaTime,Space.World);178 179         //跟新标准化向量的引用180         normalizedVelicity = velocity.normalized;181     }182 183 184 185 }

群组控制器(头鸟):

 1 using UnityEngine; 2 using System.Collections; 3  4 /// <summary> 5 /// 头鸟决定飞行的整体方向,在unityflock中被origin引用 6 /// </summary> 7 public class UnityFlockController : MonoBehaviour 8 { 9 10     public Vector3 offset;//偏移11     public Vector3 bound;//范围12     public float speed = 100.0f;13 14     private Vector3 initialPosition;15     private Vector3 nextMovementPoint;16 17     //18     19     // Use this for initialization20     void Start ()21     {22         initialPosition = transform.position;23         CalculateNextMovementPoint();24     }25     26     // Update is called once per frame27     void Update () {28         transform.Translate(Vector3.forward*speed*Time.deltaTime);29         transform.rotation=Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(nextMovementPoint-transform.position),1.0f*Time.deltaTime );//调整飞行角度30 31         if(Vector3.Distance(nextMovementPoint,transform.position)<=10.0f)32         {33                     CalculateNextMovementPoint();34         }35 36     }37 38     void CalculateNextMovementPoint()39     {40         float posx = Random.Range(initialPosition.x - bound.x, initialPosition.x + bound.x);41         float posy = Random.Range(initialPosition.y - bound.y, initialPosition.y + bound.y);42         float posz = Random.Range(initialPosition.z - bound.z, initialPosition.z + bound.z);43 44         nextMovementPoint = initialPosition + new Vector3(posx, posy, posz);45     }46 }

 

 

效果:

技术分享

游戏AI之群组行为