zoukankan      html  css  js  c++  java
  • 游戏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 }

    效果:

  • 相关阅读:
    全排列(next_permutation)
    Codeforces Round #321 (Div. 2)C(tree dfs)
    cf_ducational Codeforces Round 16_D(gcd)
    cf455a(简单dp)
    cf584a(水题)
    cf112a(水题)
    冒泡排序
    Python内置类型性能分析
    常见时间复杂度
    MongoDB 备份
  • 原文地址:https://www.cnblogs.com/Firepad-magic/p/5862486.html
Copyright © 2011-2022 走看看