Unity人工智能学习—确定性AI算法之追踪算法三

CSDN个人博客地址,凯尔八阿哥栏http://blog.csdn.net/zhangxiao13627093203,转载请注明出处

接下来就是要进行更为精准更智能的追踪。因此,在接下来的代码演示Demo中我重新设计了几个类,一个是PlayObject,这个类其实也没有什么新的东西,都是之前已经介绍过的,无非就是速度向量、位置以及移动控制等它的代码设计如下:

</pre><span style="font-size:24px"></span><pre name="code" class="csharp">using UnityEngine;
using System.Collections;

public class PlayObject : MonoBehaviour
{
    [HideInInspector]
    public float moveVx;//x方向的分速度
    [HideInInspector]
    public float moveVy;//y方向的分速度
    /// <summary>
    /// 2维坐标(x,y)
    /// </summary>
    public Vector2 Position
    {
        get
        {
            return new Vector2(this.transform.position.x, this.transform.position.y);
        }
    }
    private Vector2 _vHeading;
    /// <summary>
    /// //设置导弹的前进方向的归一化向量m_vHeading
    /// </summary>
    public Vector2 vHeading
    {
        get
        {
            float length = Mathf.Sqrt(moveVx * moveVx + moveVy * moveVy);
            if (length != 0)
            {
                _vHeading.x = moveVx / length;
                _vHeading.y = moveVy / length;
            }
            return _vHeading;
        }
    }
    private Vector2 _vSide;
    /// <summary>
    /// 前进方向的垂直向量
    /// </summary>
    public Vector2 vSide
    {
        get
        {
            _vSide.x = -vHeading.y;
            _vSide.y = vHeading.x;
            return _vSide;
        }
    }

    /// <summary>
    /// 速度向量
    /// </summary>
    public Vector2 Velocity
    {
        get
        {
            return new Vector2(moveVx, moveVy);
        }
    }
    /// <summary>
    /// 速度标量
    /// </summary>
    public float Speed
    {
        get
        {
            return Mathf.Sqrt(moveVx * moveVx + moveVy * moveVy);
        }
    }
    public float MaxSpeedRate;
    // Use this for initialization
    void Start()
    {


    }

    // Update is called once per frame
    void Update()
    {

    }
    /// <summary>
    /// 移动物体
    /// </summary>
    /// <param name="speedRate">移动的速度率,一般为1</param>
    /// <param name="isLookAtVelocityVector">是否要这是速度矢量与物体的朝向一致</param>
    public void Move(float speedRate, bool isLookAtVelocityVector)
    {
        this.transform.position += new Vector3(moveVx * Time.deltaTime, moveVy * Time.deltaTime, 0) * speedRate;
        //  Debug.Log("x:" + m_postion.x + "y:" + m_postion.y);
        //调整导弹的朝向是的它和速度矢量合成方向一样
        if (isLookAtVelocityVector)
        {
            LookAtVelocityVector();
        }
    }
    /// <summary>
    /// 使得物体始终朝向矢量速度的方向
    /// </summary>
    void LookAtVelocityVector()
    {
        float zAngles = Mathf.Atan(moveVx / moveVy) * (-180 / Mathf.PI);
        if (moveVy == 0)
        {
            zAngles = moveVx > 0 ? -90 : 90;
            //跟以往的计算角度不同的是,这里加了moveVx==0的独立判断,这样可以在不控制的时候保持原状态
            if (moveVx == 0)
            {
                zAngles = this.transform.rotation.eulerAngles.z;
            }
        }

        if (moveVy < 0)
        {
            zAngles = zAngles - 180;
        }
        Vector3 tempAngles = new Vector3(0, 0, zAngles);
        Quaternion tempQua = this.transform.rotation;
        tempQua.eulerAngles = tempAngles;
        this.transform.rotation = tempQua;
    }
}


 

这样就可以很方便的操作我们的控制对象,作为使用例子我写了一个鼠标点击追踪算法,效果如图所示

它的核心代码如下:

<span style="font-size:24px;">using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class AISeek : MonoBehaviour {
    public PlayObject plane;
    public Image Aim;
    public float vecChangeRate;//这个数值越大在目标点的穿梭次数就会越多,一般为1
    public float MaxSpeed;
    public float FleeDistance;
    Vector2 AimPos;
	// Use this for initialization
	void Start () {
        AimPos = new Vector2(Aim.transform.position.x, Aim.transform.position.y);
	
	}
	
	// Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Aim.transform.position = Input.mousePosition;
            AimPos = new Vector2(Aim.transform.position.x, Aim.transform.position.y);
        }
        Vector2 moveVec = AI_Seek(AimPos);
        float length = Mathf.Sqrt(moveVec.x * moveVec.x + moveVec.y * moveVec.y);
        if (length != 0)
        {
            //   Debug.Log("x:" + moveVec.x + "y:" + moveVec.y);
            plane.moveVx += vecChangeRate * moveVec.x / length;
            plane.moveVy += vecChangeRate * moveVec.y / length;

        }
        plane.Move(1, true);
    }
    Vector2 AI_Seek(Vector2 targetPos)
    {
        Vector2 vSeekPos = targetPos - plane.Position;
        vSeekPos = vSeekPos.normalized*MaxSpeed - plane.Velocity;
        return vSeekPos;
    }
}
</span>

它的原理是:首先计算预期的速度,这个速度是智能体在理想化情况下到达目标位置所需的速度,它是从智能体到目标的向量,大小为智能体的最大速度,该方法返回的操控力是所需要的力,当把它加到智能体当前速度向量上就得到预期的速度。所以,你可以简单的从预期速度中减去智能体的当前速度。但是你很快就会发现这个算法的一个问题,就是飞机在到达指定目标位置后并没有停止下来,而是反复的往返穿越目标点,如图所示:

针对这个问题,我会在下一篇进行讲解,接下来要讲的还是和这个算法直接相关的东西,我必须要先把它讲完。

有追踪算法,那么肯定也要有反追踪算法,其实它的原理在基于追踪的原理上就显得非常简单了

<span style="font-size:24px;">   Vector2 AI_UNSeek(Vector2 targetPos)
    {
        Vector2 disPos = plane.Position - targetPos;
        float distance = Mathf.Sqrt(disPos.x * disPos.x + disPos.y * disPos.y);
        if(distance>FleeDistance)
        {
            return Vector2.zero;
        }
        disPos = disPos.normalized * MaxSpeed - plane.Velocity;
        return disPos;
    }</span>
看看这个代码和上面的AI_Seek(vecter2 targetPos)有什么不一样。我在反追踪代码上面还加了一个距离的判断,也就是当目标和 飞机的距离小于预设的追踪距离的时候就开始追踪,它的效果图如图所示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值