鱼的聚群行为: 鱼在游动过程中会自然地聚集成群, 这也是为了保证群体的生存和躲避危害而形成的一种生活习性 鱼群的形成也是一种突现的生动示例, Reyno lds 认为鸟类和鱼类的群集的形成并不需要一个领头者, 只需要每只鸟或每条鱼遵循一些局部的相互作用规则即可, 然后群集现象作为整体模式从个体的局部的相互作用中突现出来 Reyno lds 所采用的规则有三条: 1) 分隔规则: 尽量避免与临近伙伴过于拥挤; 2) 对准规则: 尽量与临近伙伴的平均方向一致; 3) 内聚规则: 尽量朝临近伙伴的中心移动
我使用了其中1,2 条规则简单实现了下坦克分队移动的模拟逻辑如下1 监测自己与目标的距离和方向2 监测周围单位的距离和移动方向3 两个方向相加获得相量方向进行移动
工程下载(unity3d package)http://pan.baidu.com/s/1F17yQ
代码如下
组:
public class TankGroup : MonoBehaviour{
private static ListtankGroups;//所有组
public LayerMask mask;//成员层
public intgroupID=0;//组id
public floatkeepDistance=10,keepWeight=1;//成员保持距离和保持距离权重
public floattargetCloseDistance=20,targetWeight=1.25f,moveWeight=0.8f;//距离目标距离,距离目标权重和成员移动权重
}
坦克成员public class TankBehaviour : MonoBehaviour{
private const floatminMoveCheck=0.2f;
public int groupId=0;//组 id
public float moveSpeed=5, rotateSpeed=20;//移动旋转速度
public Vector3position{
get{returntransform.position;}
}
public Vector3movement{
get{returnmyMovement;}
}
private Vector3myMovement=Vector3.zero;
private TankGroupmyGroup;
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 (){
Vector3displacement=myGroup.targetPosition-position;//获取目标距离
Vector3direction=displacement.normalized*myGroup.targetWeight;//方向*权重
if(displacement.magnitude//重新计算目的地距离权重
direction*=displacement.magnitude/myGroup.targetCloseDistance;
direction+=GetGroupMovement();//获取周围组的移动
if((myGroup.targetPosition-position).magnitude//计算移动速度
tgtSpeed=0;
else
tgtSpeed=moveSpeed;
speed=Mathf.Lerp(speed,tgtSpeed,2*Time.deltaTime);
Drive(direction, speed);//移动
}
private Vector3GetGroupMovement(){
Collider[]c=Physics.OverlapSphere(position,myGroup.keepDistance,myGroup.mask);//获取周围成员
Vector3 dis,v1=Vector3.zero, v2=Vector3.zero;
for(int i=0; i
TankBehaviour otherTank=c[i].GetComponent();
dis=position-otherTank.position;//距离
v1+=dis.normalized*(1-dis.magnitude/myGroup.keepDistance);//查看与周围单位的距离
v2+=otherTank.movement;//查看周围单位移动方向
Debug.DrawLine(position, otherTank.position,Color.yellow);
}
returnv1.normalized*myGroup.keepWeight+v2.normalized*myGroup.moveWeight;//添加权重因素
}
private void Drive(Vector3 direction,float spd){
Vector3 finialDirection=direction.normalized;
float finialSpeed=spd,finialRotate=0;
floatrotateDir=Vector3.Dot(finialDirection,transform.right);
floatforwardDir=Vector3.Dot(finialDirection,transform.forward);
if(forwardDir<<span>0)
rotateDir=Mathf.Sign(rotateDir);
if(forwardDir<<span>-0.2f)
finialSpeed=Mathf.Lerp(currentSpeed,-spd*8,4*Time.deltaTime);
if(forwardDir<<span>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;
}
}