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 }

    效果:

  • 相关阅读:
    WSP部署错误—SharePoint管理框架中的对象“SPSolutionLanguagePack Name=0”依赖其他不存在的对象
    Elevate Permissions To Modify User Profile
    Error with Stsadm CommandObject reference not set to an instance of an object
    ASP.NET MVC3添加Controller时没有Scaffolding options
    测试使用Windows Live Writer写日志
    配置TFS 2010出现错误—SQL Server 登录的安全标识符(SID)与某个指定的域或工作组帐户冲突
    使用ADO.NET DbContext Generator出现错误—Unable to locate file
    CSS
    HTML DIV标签
    数据库
  • 原文地址:https://www.cnblogs.com/Firepad-magic/p/5862486.html
Copyright © 2011-2022 走看看