鱼群算法代码理解【校园作业】
匿名
【声明!】
本博客内容仅为学校要求提交的内容,所有包含着此声明的博文或多或少为“学业要求”的产品,与个人所想展现的想法无关,所有含此声明的博文将在毕业后存档删除。
若因此行为而给大家带来了不快,本人深表歉意。
以下正文
本针对的代码是2012-11-30所发表的一篇博文
http://blog.sina.com.cn/s/blog_4a2183a60101avwt.html
其个人主页:傻逗的博客
http://blog.sina.com.cn/wolfshadow2005
(不知是否为2转)
一、代码主旨
鱼群算法根据鱼类的活动特点, 提出了一种基于动物行为的自治体寻优模式
鱼的聚群行为: 鱼在游动过程中会自然地聚集成群, 这也是为了保证群体的生存和躲避危害而形成的
一种生活习性 鱼群的形成也是一种突现的生动示例, Reyno lds 认为鸟类和鱼类的群集的形成并不需要
一个领头者, 只需要每只鸟或每条鱼遵循一些局部的相互作用规则即可, 然后群集现象作为整体模式从个
体的局部的相互作用中突现出来 Reyno lds 所采用的规则有三条:
1) 分隔规则: 尽量避免与临近伙伴过于拥挤;
2) 对准规则: 尽量与临近伙伴的平均方向一致;
3) 内聚规则: 尽量朝临近伙伴的中心移动
逻辑如下
1 监测自己与目标的距离和方向
2 监测周围单位的距离和移动方向
3 两个方向相加获得相量方向进行移动
二、源代码【其实是已经修改过的,真正的源代码请去原博】
1 using UnityEngine;
2 using System.Collections;
3 using System.Collections.Generic;
4
5
6 public class TankGroup : MonoBehaviour {
7 private static List<TankGroup> tankGroups;//所有组
8
9 public LayerMask mask;//成员层
10 public int groupID=0;//组id
11 public float keepDistance=(Random.Range(7, 15)), keepWeight=1;//成员保持距离和保持距离权重
12 public float targetCloseDistance=(20f),targetWeight=(1f), moveWeight=0.8f;//距离目标距离,距离目标权重和成员移动权重
13 //~ public Color color=Color.green;
14
15 public Vector3 targetPosition{//位置
16 get{return transform.position;}
17 }
18
19 public static void AddGroup(TankGroup group){
20 if(tankGroups==null)
21 tankGroups=new List<TankGroup>();
22
23 if(!tankGroups.Contains(group))
24 tankGroups.Add(group);
25 }
26
27 public static TankGroup GetTankGroup(int index){
28 if(tankGroups==null)
29 tankGroups=new List<TankGroup>(Object.FindObjectsOfType(typeof(TankGroup))as TankGroup[]);
30
31 for(int i=0; i<tankGroups.Count; i++)
32 if(tankGroups[i].groupID==index)
33 return tankGroups[i];
34
35 throw new System.Exception("groupID not find");
36 }
1 using UnityEngine;
2 using System.Collections;
3
4 public class MoveGroup : MonoBehaviour {
5
6 public Transform group;
7
8 // Use this for initialization
9 void Start () {
10
11 }
12
13 // Update is called once per frame
14 void Update () {
15 if(Input.GetMouseButtonDown(0)){
16 Ray ray=Camera.main.ScreenPointToRay(Input.mousePosition);
17 RaycastHit hit;
18 if(Physics.Raycast(ray, out hit))
19 group.position=hit.point;
20
21 }
22 }
23 }
using UnityEngine;
using System.Collections;
public class TankBehaviour : MonoBehaviour {
private const float minMoveCheck = 0.2f;
public int groupId = 0;//组 id
public float moveSpeed = (Random.Range(4, 8)), rotateSpeed = (Random.Range(17, 28));//移动旋转速度
public Vector3 position{
get{return transform.position;}
}
public Vector3 movement{
get{return myMovement;}
}
private Vector3 myMovement=Vector3.zero;
private TankGroup myGroup;
private float tgtSpeed=0, speed=0, currentSpeed;
public void SetGroup(int index){
myGroup=TankGroup.GetTankGroup(index);
}
// Use this for initialization
void Start () {
SetGroup(groupId);
}
// Update is called once per frame
void Update () {
Vector3 displacement=myGroup.targetPosition-position;//获取目标距离
Vector3 direction=displacement.normalized*myGroup.targetWeight;//方向*权重
if(displacement.magnitude<myGroup.targetCloseDistance)//重新计算目的地距离权重
direction*=displacement.magnitude/myGroup.targetCloseDistance;
direction+=GetGroupMovement();//获取周围组的移动
if((myGroup.targetPosition-position).magnitude<minMoveCheck)//计算移动速度
tgtSpeed=0;
else
tgtSpeed=moveSpeed;
speed=Mathf.Lerp(speed,tgtSpeed,2*Time.deltaTime);
Drive(direction, speed);//移动
}
private Vector3 GetGroupMovement(){
Collider[] c=Physics.OverlapSphere(position,myGroup.keepDistance,myGroup.mask);//获取周围成员
Vector3 dis,v1=Vector3.zero, v2=Vector3.zero;
for(int i=0; i<c.Length; i++){
TankBehaviour otherTank=c[i].GetComponent<TankBehaviour>();
dis=position-otherTank.position;//距离
v1+=dis.normalized*(1-dis.magnitude/myGroup.keepDistance);//查看与周围单位的距离
v2+=otherTank.movement;//查看周围单位移动方向
Debug.DrawLine(position, otherTank.position, Color.yellow);
}
return v1.normalized*myGroup.keepWeight+v2.normalized*myGroup.moveWeight;//添加权重因素
}
private void Drive(Vector3 direction, float spd){
Vector3 finialDirection=direction.normalized;
float finialSpeed=spd, finialRotate=0;
float rotateDir=Vector3.Dot(finialDirection,transform.right);
float forwardDir=Vector3.Dot(finialDirection,transform.forward);
if(forwardDir<0)
rotateDir=Mathf.Sign(rotateDir);
if(forwardDir<-0.2f)
finialSpeed=Mathf.Lerp(currentSpeed,-spd*8,4*Time.deltaTime);
if(forwardDir<0.98f)//防抖
finialRotate=Mathf.Clamp(rotateDir*180,-rotateSpeed, rotateSpeed);
finialSpeed*=Mathf.Clamp01(direction.magnitude);
finialSpeed*=Mathf.Clamp01(1-Mathf.Abs(rotateDir)*0.8f);
transform.Translate(Vector3.forward*finialSpeed*Time.deltaTime);
transform.Rotate(Vector3.up*finialRotate*Time.deltaTime);
currentSpeed=finialSpeed;
myMovement=direction*finialSpeed;
}
}
三、代码理解
因为是unity所以其代码均为面向对象的脚本,public int等均为参数所以无法进行改进,原博主所针对的仅为代码的实现是一个教学博文所以有不足非常的正常,也正因为如此这段代码才可以进行更改。
鱼群算法跟鸟群算法在本人的理解范围内是同样的一种概念,即一群对象的群体移动算法,原bo针对的是实现,对象是模拟坦克在2维平面的移动,转向&移动缓慢,算法简单由random随即定位,整个项目运行略显单一。
改进后物件判定范围立体化,结合立体的随机生成,泛用性将更强。
四、增量设计(懒的开发)
改进后的代码立体化但是运行时行动模式单一,移动方式类似平移,效果差,于是增量设计如下:
周期性速度随机:利用状态代码&复数random给予一个随机的移动状态,结合当时时间决定整体的移动速率【时间算法】
指定一个整体的移动方向:新增2个目标变量,在鸟群中是目的地的优先度,在鱼群中是食物所在地,两一个变量则是双方所厌恶的事务比如乱流捕食者等。
争对这个代码的实现需写一个全新的代码来实现危险距离判定与喜好之物的距离判定,可能需要在TankBehaviour 与MoveGroup 上进行修改。
动画速率与模式切换:原bo的目标对象仅仅是一个物体,所以放入Unity工程中时,对象动画的优化就非常重要,毕竟速率2与速率1的物体是同一个动画速率就会非常的诡异,所以新增一个脚本挂在TankGroup上,根据TankBehaviour新增的代码的移动速度决定动画速度,并在速率高达一定值&低于一定值&转向角度的数指 来决定移动动画的选择,对鱼而言时摆尾速度&方向,对鸟类而言是振翅速度与角度
暂定上述
五、感想
其实也没有什么特别的感想,对于代码的理解什么的,只要参与工程其中配合部分注释就能简单的理解;而至于增量设计开发,成熟的软件与插件不需要第三者的增量开发,毕竟不是用户不是开发者,增量非必须需求;只能在案例&教程代码做做增量的样子(雾)
以上OVER