群组行为指的是多个对象组队同时进行的情况。每个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. RfcDestinationManager.UnregisterDestinationConfiguration时报错cannot unregister the given destination configuration

    在使用NCO访问SAP的RFC时,我的程序代码是这么写的: string destinationName = "EWM_700_GROUP"; IDestinationConfig ...

  2. Node.js_06 express

    一.初探 1 express是什么 Express.js 框架是目前最流行的node.js后端框架之一, 相当于jQuery和js之间的关系; Express 不对 Node.js 已有的特性进行二次 ...

  3. sql中UNION和UNION ALL的区别

    写sql时我们经常会遇到需要把从多张表查询的集果集进行合并.这时就用到了union.使用union或union all 时一定要保证查询的列的一致性 .不然sql会报错.字段不一致的话可以用单引号来占 ...

  4. Mybatis 原始dao CRUD方法

    用到的相关jar包及所用版本如下: 其中的Mybatis可以到github.com的网站下载 <project xmlns="http://maven.apache.org/POM/4 ...

  5. 学习笔记(1)centos7 下安装nginx

    学习笔记(1)centos7 下安装nginx 这里我是通过来自nginx.org的nginx软件包进行安装的. 1.首先为centos设置添加nginx的yum存储库 1.通过vi命令创建一个rep ...

  6. ubuntu包管理机制

    1 ubuntu包管理机制 跟大家分享一下ubuntu的软件管理机制.如果你们有过: apt-get install 或者 apt-get update 失败的经历. 在众多的apt命令中迷失. 疑惑 ...

  7. MySQL学习之用户管理

    用户权限管理 用户权限管理:在不同的项目中给不同的角色(开发者)不同的操作权限,为了保证数据库数据的安全. 简单点说:有的用户可以访问并修改这个数据,而有些用户只能去查看数据,而不能修改数据.就如同博 ...

  8. SQL优化例子

    如下SQL的优化: select count(*) from ( select id,name,col1,col2 from t1  where name='xxxx' union select id ...

  9. 爬取豆瓣电影Top250

    1 import json import requests from requests.exceptions import RequestException import re import time ...

  10. window安装ubuntu系统