游戲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         else
148         {
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 initialization
20     void Start ()
21     {
22         initialPosition = transform.position;
23         CalculateNextMovementPoint();
24     }
25     
26     // Update is called once per frame
27     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 }

 

 

效果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM