个体AI角色的操控行为de实现
2.7 FollowPath 路径跟随
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*路径跟随
* 将当前路点设置为路点列表中的第一个路点,用靠近行为产生操控力来靠近这个路点,然后寻找下一个路点
* 需要设置一个“路点半径”参数,即AI角色距离当前路点多远时,可以认为它已经到达当前路点
*/
public class SteeringFollowPath : Steering{
//有节点数组表示的路径
public GameObject[] waypoints = new GameObject[4];
//目标点
private Transform target;
//当前路点
private int currentNode;
//与路点的距离小于这个值时,认为已经到达,可以向下一个路点触发;
private float arriveDistance;
private float sqrArriveDistance;
//路点的数量
private int numberOfNodes;
//操控力
private Vector3 force;
//预期速度
private Vector3 desiredVelocity;
private Vehicle m_vehicle;
private float maxSpeed;
private bool isPlanar;
//当与目标小于这个距离时,开始减速
public float slowDownDistance;
// Use this for initialization
void Start () {
//存储路点数组中的路点个数
numberOfNodes = waypoints.Length;
m_vehicle = GetComponent<Vehicle>();
maxSpeed = m_vehicle.maxSpeed;
isPlanar = m_vehicle.isPlanar;
//设置当前路点为第0个路点
currentNode = 0;
//设置当前路点为目标点
target = waypoints[currentNode].transform;
arriveDistance = 1.0f;
sqrArriveDistance = arriveDistance * arriveDistance;
}
public override Vector3 Force()
{
force = new Vector3(0, 0, 0);
Vector3 dist = target.position - transform.position;
if (isPlanar)
dist.y = 0;
//如果当前路点已经是路点数组中的最后一个;
if (currentNode == numberOfNodes - 1)
{
//如果与当前路点的距离大于减速距离
if (dist.magnitude > slowDownDistance)
{
//取出预期速度
desiredVelocity = dist.normalized * maxSpeed;
//计算操纵向量
force = desiredVelocity - m_vehicle.velocity;
}
else
{
//与当前路点距离小于减速距离,开始减速,计算操控向量
desiredVelocity = dist - m_vehicle.velocity;
force = desiredVelocity - m_vehicle.velocity;
}
}
else
{
//当前路点不是路点数组中的最后一个,即正走向中间路点
if (dist.sqrMagnitude < slowDownDistance)
{
//如果与当前路点距离的平方小于到达距离的平方
//可以开始靠近下一个路点,将下一个路点设置为目标点
currentNode++;
target = waypoints[currentNode].transform;
}
//计算预期速度与操控向量
desiredVelocity = dist.normalized * maxSpeed;
force = desiredVelocity - m_vehicle.velocity;
}
return force;
}
// Update is called once per frame
void Update () {
}
}
2.8 CollisionAvoidance 避开障碍
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*避开障碍
* AI行进路线发现比较近的障碍时,产生一个“排斥了力”,使AI角色远离这个障碍物
* 计算方法:
* 与计算除一条静态可行路线的寻路算法不同,操控行为使一种动态路线,对躲避L或T形障碍物效果不是很好,而合力的作用使得任何操控力都不能
* 单独决定AI角色的运动,虽然概率较小,但如果游戏中要保证完全不发生碰撞,更好的选择使采用寻路算法
*/
public class SteeringForCollisionAvoidance : Steering {
public bool isPlaner;
private Vector3 desiredVelocity;
private Vehicle m_vehicle;
private float maxSpeed;
private float maxForce;
//避免障碍所产生的操控力
public float avoidanceForce;
//能向前看到的最大距离
public float MAX_SEE_AHEAD = 2.0f;
//场景中的所有碰撞体组成的数组
private GameObject[] allColliders;
// Use this for initialization
void Start () {
m_vehicle = GetComponent<Vehicle>();
maxSpeed = m_vehicle.maxSpeed;
maxForce = m_vehicle.maxForce;
isPlaner = m_vehicle.isPlanar;
//如果避免障碍所产生的操控力大于最大操控力,将它截断到最大操控力
if (avoidanceForce > maxForce)
avoidanceForce = maxForce;
//存储场景中的所有碰撞体,即Tag为obstacle的那些游戏体
allColliders = GameObject.FindGameObjectsWithTag("obstacle");
}
public override Vector3 Force()
{
RaycastHit hit;
Vector3 force = new Vector3(0, 0, 0);
Vector3 velocity = m_vehicle.velocity;
Vector3 normalizedVelocity = velocity.normalized;
//画出一条射线,需要考查与这条射线相交的碰撞体
Debug.DrawLine(transform.position, transform.position + normalizedVelocity * MAX_SEE_AHEAD * (velocity.magnitude / maxSpeed));
if (Physics.Raycast(transform.position, normalizedVelocity, out hit, MAX_SEE_AHEAD * velocity.magnitude / maxSpeed))
{
//如果射线与某个碰撞体相交,表示可能与该碰撞体发生碰撞
Vector3 ahead = transform.position + normalizedVelocity * MAX_SEE_AHEAD * (velocity.magnitude / maxSpeed);
//计算避免碰撞所需的操控力
force = ahead - hit.collider.transform.position;
force *= avoidanceForce;
if (isPlaner)
{
force.y = 0;
}
//将这个碰撞体的颜色变为绿色,其他的都变为灰色
foreach(GameObject c in allColliders)
{
if (hit.collider.gameObject == c)
{
c.GetComponent<Renderer>().material.color = Color.black;
}
else
c.GetComponent<Renderer>().material.color = Color.white;
}
}
else
{
//如果向前看的有限范围内,没有发生碰撞的可能
//将所有碰撞体设为灰色
foreach(GameObject c in allColliders)
{
c.GetComponent<Renderer>().material.color = Color.white;
}
}
return force;
}
// Update is called once per frame
void Update () {
}
}