第三步
创建一个空物体,起名为follersGenerator,用于生成跟随者,并添加脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GenerateBotsForFollowLeader : MonoBehaviour { public GameObject botPrefab; public GameObject leader; public int botCount; public float minX = -5f; public float maxX = 5.0f; public float minZ = -5.0f; public float maxZ = 5.0f; public float Yvalue = 1.026003f; void Start() { Vector3 spawnPosition; GameObject bot; for(int i = 0; i < botCount; i++) { spawnPosition = new Vector3(Random.Range(minX, maxX), Yvalue, Random.Range(minZ, maxZ));//随机产生一个生成位置 bot = Instantiate(botPrefab, spawnPosition, Quaternion.identity) as GameObject; bot.GetComponent<SteeringForLeaderFollowing>().leader = leader; bot.GetComponent<SteeringForEvade>().target = leader; bot.GetComponent<SteeringForEvade>().enabled = false; bot.GetComponent<EvadeController>().leader = leader; } } }
第四步
创建一个方块预设,作为跟随者,挂上下列脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class AILocomotion : Vehicle { private CharacterController controller; //AI�Ľ�ɫ������ private Rigidbody theRigidbody; private Vector3 moveDistance;//AI��ɫÿ�ε��ƶ����� void Start() { controller = GetComponent<CharacterController>(); theRigidbody = GetComponent<Rigidbody>(); moveDistance = new Vector3(0, 0, 0); base.Start();//���û����start��������������ij�ʼ�� } //������ز�����FixedUpdate�и��� void FixedUpdate() { velocity += acceleration * Time.fixedDeltaTime;//�����ٶ� if (velocity.sqrMagnitude > sqrMaxSpeed) //��������ٶ� velocity = velocity.normalized * maxSpeed; moveDistance = velocity * Time.fixedDeltaTime; if (isPlanar) { velocity.y = 0; moveDistance.y = 0; } if (controller != null)//����Ѿ�ΪAI��ɫ���ӽ�ɫ����������ô���ý�ɫ������ʹ���ƶ� controller.SimpleMove(velocity); //�����ɫ��û��ɫ��������ҲûRigidbody //����Rigidbody����Ҫ�ɶ���ѧ�ķ�ʽ�������ƶ� else if (theRigidbody == null || !theRigidbody.isKinematic) transform.position += moveDistance; else //��Rigidbody���ƽ�ɫ���˶� theRigidbody.MovePosition(theRigidbody.position+moveDistance); if(velocity.sqrMagnitude>0.00001)//���³�������ٶȴ���һ����ֵ��Ϊ�˷�ֹ������ { Vector3 newForward = Vector3.Slerp(transform.forward, velocity, damping * Time.deltaTime); if(isPlanar) newForward.y = 0; transform.forward = newForward; } //�������߶��� gameObject.GetComponent<Animation>().Play("walk"); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SteeringForArrive : Steering { public bool isPlanar = true; public float arrivalDistance = 0.3f; public float characterRadius = 1.2f; public float slowDownDistance; public GameObject target; private Vector3 desiredVelocity;//预期速度 private Vehicle m_vehicle;//获得被操控的AI角色 private float maxSpeed; void Start() { m_vehicle = GetComponent<Vehicle>(); maxSpeed = m_vehicle.maxSpeed; isPlanar = m_vehicle.isPlanar; } public override Vector3 Force() { Vector3 toTarget = target.transform.position - transform.position; Vector3 desiredVelocity; Vector3 returnForce; if (isPlanar) toTarget.y = 0; float distance = toTarget.magnitude; if (distance > slowDownDistance) { desiredVelocity = toTarget.normalized * maxSpeed; returnForce = desiredVelocity - m_vehicle.velocity; } else { desiredVelocity = toTarget - m_vehicle.velocity; returnForce = desiredVelocity - m_vehicle.velocity; } return returnForce; } void OnDrawGizmos() { Gizmos.DrawWireSphere(target.transform.position, slowDownDistance); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(SteeringForArrive))] public class SteeringForLeaderFollowing : Steering { public Vector3 target; private Vector3 desiredVelocity;//预期速度 private Vehicle m_vehicle;//获得被操控的AI角色 private float maxSpeed; private bool isPlanar; public GameObject leader; private Vehicle leaderController; private Vector3 leaderVelocity; private float LEADER_BEHIND_DIST=2.0f; private SteeringForArrive arriveScript; private Vector3 randomOffset; void Start() { m_vehicle = GetComponent<Vehicle>(); maxSpeed = m_vehicle.maxSpeed; isPlanar = m_vehicle.isPlanar; leaderController=leader.GetComponent<Vehicle>(); arriveScript= GetComponent<SteeringForArrive>();//为抵达行为指定目标点 arriveScript.target = new GameObject("arriveTarget"); arriveScript.target.transform.position = leader.transform.position; } public override Vector3 Force() { leaderVelocity = leaderController.velocity; target=leader.transform.position+LEADER_BEHIND_DIST*(-leaderVelocity).normalized;//计算目标点 arriveScript.target.transform.position = target; return new Vector3(0, 0, 0); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Radar : MonoBehaviour { private Collider[] colliders;//碰撞体的组数 private float timer = 0;//计时器 public List<GameObject> neighbors; public float checkInterval = 0.3f;//设置检测的时间间隔 public float detectRadius = 10f;//设置邻域半径 public LayerMask layersChecked;//设置检测哪一层的游戏对象 void Start() { neighbors = new List<GameObject>(); } void Update() { timer += Time.deltaTime; if(timer > checkInterval) { neighbors.Clear(); colliders = Physics.OverlapSphere(transform.position, detectRadius, layersChecked);//查找当前AI角色邻域内的所有碰撞体 for(int i = 0; i < colliders.Length; i++)//对于每个检测到的碰撞体,获取Vehicle组件,并且加入邻居列表钟 { if (colliders[i].GetComponent<Vehicle>()) neighbors.Add(colliders[i].gameObject); } timer = 0; } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SteeringForSeparation : Steering { public float comforDistance = 1;//可接受的距离 public float multiplierInsideComfortDistance = 2;//当AI角色与邻居距离过近时的惩罚因子 public override Vector3 Force() { Vector3 steeringForce = new Vector3(0, 0, 0); foreach(GameObject s in GetComponent<Radar>().neighbors)//遍历这个AI角色的邻居列表中的每个邻居 { if ((s != null) && (s != this.gameObject)) { Vector3 toNeighbor = transform.position - s.transform.position;//计算当前AI角色与邻居s之间的距离 float length=toNeighbor.magnitude; steeringForce += toNeighbor.normalized / length;//计算这个邻居引起的操控力 if (length < comforDistance) steeringForce *= multiplierInsideComfortDistance; } } return steeringForce; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SteeringForEvade :Steering { public GameObject target; private Vector3 desiredVelocity;//预期速度 private Vehicle m_vehicle;//获得被操控的AI角色 private float maxSpeed; void Start() { m_vehicle = GetComponent<Vehicle>(); maxSpeed = m_vehicle.maxSpeed; } public override Vector3 Force() { Vector3 toTarget = target.transform.position - transform.position; float lookaheadTime = toTarget.magnitude / (maxSpeed + target.GetComponent<Vehicle>().velocity.magnitude);//向前预测的时间 desiredVelocity = (transform.position - (target.transform.position+target.GetComponent<Vehicle>().velocity*lookaheadTime)).normalized * maxSpeed; return (desiredVelocity - m_vehicle.velocity); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EvadeController : MonoBehaviour { public GameObject leader; private Vehicle leaderLocomotion; private Vehicle m_vehicle; private bool isPlanar; private Vector3 leaderAhead; private float LEADER_BEHIND_DIST; private Vector3 dist; public float evadeDistance; private float sqrEvadeDistance; private SteeringForEvade evadeScript; void Start() { leaderLocomotion = leader.GetComponent<Vehicle>(); evadeScript= GetComponent<SteeringForEvade>(); m_vehicle= GetComponent<Vehicle>(); isPlanar=m_vehicle.isPlanar; LEADER_BEHIND_DIST = 2.0f; sqrEvadeDistance=sqrEvadeDistance*sqrEvadeDistance; } void Update() { leaderAhead=leader.transform.position+leaderLocomotion.velocity.normalized*LEADER_BEHIND_DIST; //计算领队前方的一个点 dist = transform.position - leaderAhead; if (isPlanar) { dist.y = 0; } if(dist.sqrMagnitude < sqrEvadeDistance) { evadeScript.enabled = true; Debug.DrawLine(transform.position, leader.transform.position); } else { evadeScript.enabled = false; } } }
收尾
最后再给各个角色装上刚体,设置好Leader等参数就可以了。
很多行为我们都可以通过设定规则来实现,可能乍一看行为很难摸索,但慢慢分析出其中的规则并逐一实现后,问题往往就会被解决