游戏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 }

效果:

时间: 2024-12-25 05:43:34

游戏AI之群组行为的相关文章

如何建立一个完整的游戏AI

http://blog.friskit.me/2012/04/how-to-build-a-perfect-game-ai/ 人工智能(Artificial Intelligence)在游戏中使用已经很多年了,并且到现在越来越完善.如果你不在你的游戏中加入完善的游戏智能,那么别人就认为你的游戏缺少可玩性.在游戏中,AI并不一定要包括神经网络,学习系统和复杂的数学结构,游戏AI只是游戏中一个重要部分,它是活动的,并不是科学性质的.我认为如何建立一个游戏AI,最主要的就是要明白你想在游戏中实现什么效

聊天源码IM聊天室模板 群组聊天app 即时通讯IM设计聊天

(此贴长期有效)系统提供多种方式合作,支持源码转让/支持按年整体运维合作/支持行业定制开发,更多需求请联系我们 团队Tel:15538001716 (V同) 独立IM:个性化定制,私有化部署,全功能,高并发,快速拥有自己的微信.QQ或陌陌. I M+模块:Web.H5.App.小程序,简单几步实现消息.动态.点赞评论,变身社交+电商.资讯.游戏.支付.区块链-- 独立部署!加密通道!牢牢掌握通讯信息! 后台源码采用Java开发,maven环境Nettty框架.本地MySQL,MangoDB数据库

做一个群组聊天页面

要做个群组聊天的页面,参考微信的web版本,大致就是分为左右两列,左边是群组列表,右边是群组中的对话 示例图如下: 这个页面风格是使用ACE做的,再次啧啧下,ACE真TMD强大,这个页面的风格很招人喜欢. 做这个页面刚开始的时候我走了弯路,初步想的是使用iframe,左侧群组聊天页面是页面加载的,右侧的群组对话框是个iframe.然后点击左侧的任意一个群组,右侧的对话iframe就修改src,然后更新对话的时候也超简单,直接iframe重新加载一下就ok了. 但是呢,后来发现,我这样需要写的co

使用Python创建自定义机器人向群组人员发送消息

创建机器人 打开需要创建机器人的群组,点击 群组机器 人的图标 点击 + 号键创建机器人 点击 自定义 创建自定义机器人 点击 添加 设置机器人头像,机器人名称,机器人属组,点击下一步 复制API(webhook),点击完成 编写Python脚本 注意:修改脚本内requrl的值为机器人的webhook地址 脚本使用说明: 使用方法:脚本后面跟要发送的消息 at所有人将 isAtAll 的值改为True at指定人在 atMobiles 列表定义被at人的手机,列表形式 requrl的值为机器人

棋牌源码搭建教程之棋牌游戏AI算法

棋牌游戏客户端实现采用Flash 9开发,服务端采用Win32+VC6开发(基于IOCP),数据库网关采用Win32+VC6开发(基于IOCP,MySQL5实现了处理线程池和数据库连接池).虽然服务器端去年就已经完成,但相应的机器人AI算法一直没有能力去实现.今天把它拿到Blog上来希望有机会和感兴趣的兄弟们探讨下. Kevin在他的Blog上给出了他的实现,其给出的算法思想是用宽度优先生成一棵搜索树,再根据玩牌的技巧进行剪枝与判权,机器人的AI能够像养成类游戏那样,实现在蹂躏下慢慢成长,水平逐

#Linux学习笔记# Linux文件的所有者、群组和其他人

1.关于所有者.群组和其他人 在Linux系统中,每个文件都具有User.Group和Others三种身份的权限配置.那这三种身份分别表示什么意思呢?配置这三种身份的权限有啥意义呢? (1)文件所有者(User) 由于Linux系统支持多人多任务,因此常常存在多个用户同时使用一个Linux系统的情况.那么,如何确认每个用户私密文件的访问控制呢?这就是文件所有者存在的原因. Linux系统为每个用户提供一个用户主目录,用户的主目录为/home/<username>.例如,下图的/home/lie

Linux 的账号与群组[转自vbird]

Linux 的账号与群组 管理员的工作中,相当重要的一环就是『管理账号』啦!因为整个系统都是你在管理的, 并且所有一般用户的账号申请,都必须要透过你的协助才行!所以你就必须要了解一下如何管理好一个服务器主机的账号啦! 在管理 Linux 主机的账号时,我们必须先来了解一下 Linux 到底是如何辨别每一个使用者的! 使用者标识符: UID 与 GID 虽然我们登陆 Linux 主机的时候,输入的是我们的账号,但是其实 Linux 主机并不会直接认识你的『账号名称』的,他仅认识 ID 啊 (ID

云通讯 添加群组

群组和双向回呼是一个级别的 应为他们都是属于子账户的操作 所以 他们的子帐号鉴权信息验证是一样 在sdk包里添加 /** 添加组 */ function CreateGroup($Group) { //子帐号鉴权信息验证,对必选参数进行判空. $auth=$this->subAuth(); if($auth!=""){ return $auth; } // 拼接请求包体 if($this->BodyType=="json"){ $body= "

六.用户.群组和权限

1.用户及passwd文件 a)/etc/passwd 文件的功能:存储所有用户的相关信息,该文件为用户信息数据库 b)/etc/passwd 每个字段的含义: 第一个字段:表示用户的用户名 第二个字段:如果是X,表示该用户登入系统必须使用密码,如果没有X,就无需密码即可登入 第三个字段:表示这个用户的uid 第四个字段:表示这个用户所属群组的gid 第五个字段:记录的是有关这个用户的注释信息(如全名或通信地址) 第六个字段:记录这个用户家目录的路径 第七个字段:记录这个用户登入后,第一个要执行