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

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

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

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

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

结构:

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

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

群组中的个体:

 using UnityEngine;
using System.Collections; /// <summary>
/// 该类是对群体中的每个个体行为的约束,即单个的鸟
/// </summary>
public class UnityFlock : MonoBehaviour
{ //最小速度,转向速度,随机频率,随机力
public float minSpeed = 20.0f;
public float turnSpeed = 20.0f;
public float randomFreq = 20.0f;
public float randomForce = 20.0f; //队列属性 :向心力,向心区间,吸引力
public float toOriginForce = 50.0f;
public float toOriginRange = 100.0f; public float gravity = 2.0f; //分离属性:规避力,规避半径
public float avoidanceForce = 20.0f;
public float avoidanceRadius = 50.0f; //凝聚属性:追随速度,追随半径(相对于领导者即头鸟)
public float followVelocity = 4.0f;
public float followRadius = 40.0f; //控制单个个体运动的属性:父对象即头鸟,速度,归一化速度,随机推力,父对象的推力。。。
private Transform origin;
private Vector3 velocity;
private Vector3 normalizedVelicity;
private Vector3 randomPush;
private Vector3 originPush;
private Transform[] objects;
private UnityFlock[] otherFlocks;//其他个体集合
private Transform transformCompont; // Use this for initialization
void Start ()
{
randomFreq = 1.0f/randomFreq;//获取随机变化的频率
//设置父节点为origin
origin = transform.parent; transformCompont = transform; //临时组件数组
Component[] tempFlocks = null; if (transform.parent)
{
tempFlocks = transform.parent.GetComponentsInChildren<UnityFlock>();
} objects=new Transform[tempFlocks.Length];
otherFlocks=new UnityFlock[tempFlocks.Length]; //将群体的位置信息和群体加载到数组
for (int i = ; i < tempFlocks.Length; i++)
{
objects[i] = tempFlocks[i].transform;
otherFlocks[i] = (UnityFlock)tempFlocks[i];
} transform.parent = null; StartCoroutine(UpdateRandom());
} //基于randomFreq的频率来更新randompush的频率
IEnumerator UpdateRandom()
{
while (true)
{
randomPush = Random.insideUnitSphere*randomForce;//Random.insideUnitSphere随机返回单位球体类一点坐标,配合随机力度来跟新randomPush
yield return new WaitForSeconds(randomFreq+Random.Range(-randomFreq/,randomFreq/));//依据随机频率在一定时间分为类变换randomPush
}
} // Update is called once per frame
void Update ()
{
float speed = velocity.magnitude;
Vector3 avgVelocity = Vector3.zero;
Vector3 avgPosition = Vector3.zero;
float count = ;
float f = 0.0f;
float d = 0.0f;
Vector3 myPosition = transformCompont.position;
Vector3 forceV;
Vector3 toAvg;
Vector3 wantedVel; for (int i = ; i < objects.Length; i++)
{
Transform transform = objects[i];
if (transform != transformCompont)
{
Vector3 otherPositon = transform.position; //平均位置来计算聚合
avgPosition += otherPositon;
count++; //从其他群体到这个的向量
forceV = myPosition - otherPositon; //上面向量的长度
d = forceV.magnitude; //如果向量长度比规避半径小的话,则加大推力
if (d < followRadius)
{
//如果当前的向量长度小于规定的逃离半径的话,则基于 逃离半径计算对象的速度
if (d > )
{
f = 1.0f - (d/avoidanceRadius);
avgVelocity += (forceV / d) * f * avoidanceForce;
//向量除以它的模得到自己的单位向量
} } //保持与头儿的距离
f = d/followRadius;
UnityFlock otherSealgull = otherFlocks[i]; //标准化otherSealgul的速度来获取移动的方向,接下来设置一个新的速度
avgVelocity += otherSealgull.normalizedVelicity * f *followVelocity; }
} if (count > )
{
//得到平均速度
avgVelocity /= count;
//获得平均位置与对象间的向量
toAvg = (avgPosition/count) - myPosition;
}
else
{
toAvg = Vector3.zero;
} //
forceV = origin.position - myPosition;
d = forceV.magnitude;
f = d/toOriginRange;
//
if (d > )
originPush = (forceV/d)*f*toOriginForce;
if (speed < minSpeed && speed > )
velocity = (velocity/speed)*minSpeed; wantedVel = velocity; //最终速度
wantedVel -= wantedVel*Time.deltaTime;
wantedVel += randomPush*Time.deltaTime;
wantedVel += originPush*Time.deltaTime;
wantedVel += avgVelocity*Time.deltaTime;
wantedVel += toAvg.normalized*gravity*Time.deltaTime; //调整速度使之转向最终速度
velocity = Vector3.RotateTowards(velocity, wantedVel,turnSpeed*Time.deltaTime, 100.00f); transformCompont.rotation = Quaternion.LookRotation(velocity); //移动对象
transformCompont.Translate(velocity*Time.deltaTime,Space.World); //跟新标准化向量的引用
normalizedVelicity = velocity.normalized;
} }

群组控制器(头鸟):

 using UnityEngine;
using System.Collections; /// <summary>
/// 头鸟决定飞行的整体方向,在unityflock中被origin引用
/// </summary>
public class UnityFlockController : MonoBehaviour
{ public Vector3 offset;//偏移
public Vector3 bound;//范围
public float speed = 100.0f; private Vector3 initialPosition;
private Vector3 nextMovementPoint; // // Use this for initialization
void Start ()
{
initialPosition = transform.position;
CalculateNextMovementPoint();
} // Update is called once per frame
void Update () {
transform.Translate(Vector3.forward*speed*Time.deltaTime);
transform.rotation=Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(nextMovementPoint-transform.position),1.0f*Time.deltaTime );//调整飞行角度 if(Vector3.Distance(nextMovementPoint,transform.position)<=10.0f)
{
CalculateNextMovementPoint();
} } void CalculateNextMovementPoint()
{
float posx = Random.Range(initialPosition.x - bound.x, initialPosition.x + bound.x);
float posy = Random.Range(initialPosition.y - bound.y, initialPosition.y + bound.y);
float posz = Random.Range(initialPosition.z - bound.z, initialPosition.z + bound.z); nextMovementPoint = initialPosition + new Vector3(posx, posy, posz);
}
}

效果:

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

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

    http://blog.friskit.me/2012/04/how-to-build-a-perfect-game-ai/ 人工智能(Artificial Intelligence)在游戏中使用已经 ...

  2. 游戏AI之初步介绍(0)

    目录 游戏AI是什么? 游戏AI和理论AI 智能的假象 (更新)游戏AI和机器学习 介绍一些游戏AI 4X游戏AI <求生之路>系列 角色扮演/沙盒游戏中的NPC 游戏AI 需要学些什么? ...

  3. 游戏AI玩伴,是“神队友”还是“猪队友”?

    “一代英豪”暴雪迎来了自己的暴风雪. 2月13日,动视暴雪公布了2018年全年财报.财报显示,暴雪第四季度营业收入仅为28.4亿美元,低于华尔街分析师预期的30.4亿美元.在公布了财报业绩后,该公司又 ...

  4. Omad群组部署、依赖部署一键解决

    本文来自网易云社区 作者:李培斌 前言 基于omad部署平台实现一键部署的实践已有很多成功的经验,杭研QA的技术先锋们也在ks圈里有很多不同的文章去阐述关于这类需求的实现和思路,当然包括我们金融事业部 ...

  5. 游戏AI的生命力源自哪里?为你揭开MOBA AI的秘密!

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由wataloo发表在专栏wataloo的试验田 1 设计概要 1.1 设计原则和目的 英雄AI的目的主要有: 1.新手过渡局,让玩家刚 ...

  6. 游戏AI系列内容 咋样才能做个有意思的AI呢

    游戏AI系列内容 咋样才能做个有意思的AI呢 写在前面的话 怪物AI怎么才能做的比较有意思.其实这个命题有点大,我作为一个仅仅进入游戏行业两年接触怪物AI还不到一年的程序员来说,来谈这个话题,我想我是 ...

  7. 微信小程序的机会在于重新理解群组与二维码

    历时一年,唯一一个尚未发布就获得Pony Ma与Allen Zhang站台的产品:微信小程序,将于2017年1月9日正式上线了.我很期待.唯一要警惕的是:防止长考出臭棋. 在上线前夕,我对于如何借助小 ...

  8. 趣说游戏AI开发:对状态机的褒扬和批判

    0x00 前言 因为临近年关工作繁忙,已经有一段时间没有更新博客了.到了元旦终于有时间来写点东西,既是积累也是分享.如题目所示,本文要来聊一聊在游戏开发中经常会涉及到的话题--游戏AI.设计游戏AI的 ...

  9. 使用行为树(Behavior Tree)实现游戏AI

    ——————————————————————— 谈到游戏AI,很明显智能体拥有的知识条目越多,便显得更智能,但维护庞大数量的知识条目是个噩梦:使用有限状态机(FSM),分层有限状态机(HFSM),决策 ...

随机推荐

  1. building for production...Killed

    npm run build报错 building for production...Killed 原理 按照他人的说法是,服务器内存不够用了,这样就给他配置一个单独的内存出来就解决了 解决方法 sud ...

  2. linux mysql命令行查看显示中文

    linux 命令行查看mysql的库字符集是utf8,查询某个表时,仍然是显示不了中文, 之后使用了命令 mysql>set  names utf8;就可以正常显示中文了. 如何才更好的使mys ...

  3. 基于vue脚手架的项目打包上线(发布)方法和误区

    最近要把vue脚手架开发的一个项目上线,只知道vue脚手架是基于node的服务端项目,那么只需要 npm run dev 就可以轻松启动整个项目,当我想当然的给服务器配置合适的node环境(这里也遇到 ...

  4. (一 、上)搭建简单的SpringBoot + java + maven + mysql + Mybatis+通用Mapper 《附项目源码》

    最近公司一直使用 springBoot 作为后端项目框架, 也负责搭建了几个新项目的后端框架.在使用了一段时间springBoot 后,感觉写代码 比spring 更加简洁了(是非常简洁),整合工具也 ...

  5. 产品 | What's产品经理

    如果想知道什么是产品,首先需要知道什么是缔造者.其名曰:"产品经理". PS:产品经理一词在国内大多时候泛指"互联网产品经理". 对于产品经理这一职位,说实在很 ...

  6. iOS安装CocoaPods详细过程

    iOS安装CocoaPods详细过程 一.简介 什么是CocoaPods CocoaPods是OS X和iOS下的一个第三类库管理工具,通过CocoaPods工具我们可以为项目添加被称为“Pods”的 ...

  7. 免安装版MySQL8数据库的安装

    [环境准备] PC版本:Windows10企业版.64位操作系统 数据库:MySQL8.0.12-win64.zip免安装版 [彻底卸载已安装的MySQL数据库] 由于系统中MySQL数据库的卸载不彻 ...

  8. ethereum(以太坊)(实例)--"简单的公开竞拍"

    说真的,刚开始接触这个竞拍案例--“简单的公开竞拍”,我就抱着简单的心态去查看这个实例,但是自我感觉并不简单.应该是我实力不到家的原因吧!!!233333...不过经过大半天的努力,自己理解完之后,觉 ...

  9. 安装jenkins环境之jdk8

    Launchpad PPA Repositories是很有用的非ubuntu官方的第三方个人资源库,可以很方便地安装第三方软件. 但是在运行add-apt-repository命令时,有时会提示命令不 ...

  10. 网站用户行为分析——在Ubuntu下安装MySQL及其常用操作

    安装MySQL 使用以下命令即可进行mysql安装,注意安装前先更新一下软件源以获得最新版本: sudo apt-get update #更新软件源 sudo apt-get install mysq ...