【Unity】入门学习笔记180520——人工智能(4)——个体操控(3)

个体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 () {
		
	}
}



猜你喜欢

转载自blog.csdn.net/Dylan_Day/article/details/80375827