UnityAI行为------群组行为CraigReynold算法 钢体力!
结合上一篇文章讲述群组行为的算法,这篇是替换实现,更加清晰。
FlockController的行为很简单,它在运行时生成boid的行为,更新群组的中心及群组的平均速度
public class FlockController : MonoBehaviour {
public float minVelocity = 1;
public float maxVeclocity = 8;
public int flockSize = 20;
public float centerWeight = 1;
public float velocityWeight = 1;
public float separationWeight = 1;
public float followWeight = 1;
public float randomizeWeight = 1;
public Flock perfab;
public Transform target;
public Vector3 flockCenter;
public Vector3 flockVelocity;
public ArrayList flockList = new ArrayList();
void Start () {
for(int i = 0; i < flockSize; i++)
{
Flock flock = Instantiate(perfab,transform.position,transform.rotation) as Flock;
flock.transform.parent = transform;
flock.controller = this;
flockList.Add(flock);
}
}
/*
先声明实现群组算法所需的所有属性,再基于输入的群组大小生成boid对象,和上次一样,
*/
void Update () {
Vector3 center = Vector3.zero;
Vector3 velocity = Vector3.zero;
foreach(Flock flock in flockList)
{
center += flock.transform.localPosition;
velocity += flock.transform.GetComponent<Rigidbody>().velocity;
}
flockCenter = center / flockSize;
flockVelocity = velocity / flockSize;
}
/*
在Update方法中,保持更新群组的平均中心和速度,这些值来自于我们的boid对象,它们可以用来调整与控制者的凝聚与队列属性
*/
}
下面是具有TargetMoement脚本的Target实体,稍后我们将创建这个脚本,我们选择一个附近的随机的目标点,并向其移动。当我们到达该点附近时,再选择一个新的点。这时所有boid都将跟随这个目标。
public class TargetMovement : MonoBehaviour {
public Vector3 bound;
public float speed = 100.0f;
private Vector3 initialPosition;
private Vector3 nextMovementPoint;
void Start () {
initialPosition = transform.position;
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);
}
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();
}
}
}
public class Flock : MonoBehaviour {
public FlockController controller;
private Rigidbody rigidbody;
private void Awake()
{
rigidbody = transform.GetComponent<Rigidbody>();
}
private void Start()
{
controller = transform.parent.GetComponent<FlockController>();
}
private void Update()
{
if(controller)
{
Vector3 relativePos = steer() * Time.deltaTime;
if(relativePos != Vector3.zero)
{
rigidbody.velocity = relativePos;
}
float speed = rigidbody.velocity.magnitude;
if(speed > controller.maxVeclocity)
{
rigidbody.velocity = rigidbody.velocity.normalized * controller.maxVeclocity;
}else if(speed < controller.minVelocity)
{
rigidbody.velocity = rigidbody.velocity.normalized * controller.minVelocity;
}
}
}
private Vector3 steer()
{
Vector3 center = controller.flockCenter - transform.localPosition;
Vector3 velocity = controller.flockVelocity - rigidbody.velocity;
Vector3 follow = controller.target.localPosition - transform.localPosition;
Vector3 separation = Vector3.zero;
foreach(Flock flock in controller.flockList)
{
if(flock != this)
{
Vector3 ralativePos = transform.localPosition - flock.transform.localPosition;
separation += ralativePos / (ralativePos.sqrMagnitude);
}
}
Vector3 randomize = new Vector3((Random.value * 2) - 1,(Random.value * 2) - 1,(Random.value * 2) - 1);
randomize.Normalize();
return (controller.centerWeight * center + controller.velocityWeight * velocity + controller.separationWeight * separation + controller.followWeight * follow + controller.randomizeWeight * randomize);
}
}