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

转自:http://blog.csdn.net/zhangxiao13627093203/article/details/47658673

上一篇讲到了追踪算法的比较简单的形式,看上去比较假,因为AI控制的对象过于精确地跟踪目标。一种更自然的追踪方式可以这样做,使得跟踪者的方向矢量与从跟踪目标的中心到跟踪者的中心所定义的方向矢量靠拢。如图所示:

这个算法的基本思路是这样的:假设AI控制的对象即追踪者有如下属性

1、Position:(tracker.x,tracker.y)

2、Velocity:(tracker.vx,tracker.vy)

追踪目标有如下属性:

1、Postion:(target.x,target.y)

2、Velocity:(target.vx,target.vy)

接下来就是调整追踪者的速度向量的常用逻辑:

1、计算从跟踪者到跟踪目标的向量:TV=(target.x-tracker.x,target.y-tracker.y)=(tvx,tvy),归一化TV,这样就可以得到一个单位向量,从而方便计算它与坐标轴的角度。归一化也即是sqrt(x^2+y^2).

2、调整追踪者当前的速度向量,加上一个按rate比例缩放过的TV*

tracker.x+=rate*tvx;

traker.y+=rate*tvy;

注意这一步才是关键,它使得导弹的追踪不在是从前的直接紧密追踪而是会有一个变轨迹的过程,另外当rate等于1的时候,跟踪向量会合的更快,跟踪算法对目标跟踪的根据紧密,并更快地的修正目标的运动。

3、跟踪者的速度向量修改过后,有可能向量的速度会溢出最大值。换言之,跟踪者一旦锁定了目标的方向就会继续沿着该方向加速。所以需要设置一个上限,让追踪者的速度从某处慢下来

在Unity5.1.1实现的效果图如图所示:在这里我还调整了导弹的追踪方向rotation的变化,其实如果是3D空间就可以直接使用lookAt方法来使得导弹的运动方向始终朝向目标,但是在2D平面上就没有这么好的方法供我们调用了,所以我自己写了一个算法。如果不加这个方向修正算法的结果如图所示:

导弹的运行是不是显得非常的生硬,运动的轨迹和导弹头的朝向并不一致,这一段的修正导弹头的方向的代码如下:

void LookAtTarget()
   {
       float zAngles;
       if(moveVy==0)
       {
           zAngles = moveVx >= 0 ? -90 : 90;
       }
       zAngles = Mathf.Atan(moveVx / moveVy) * (-180 / Mathf.PI);
      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;
   }

 算法的计算思路是:

注意:这个平面上的角度主要是Z轴的角度变化,而Z轴的角度是导弹头方向直线与y轴的夹角,这点比较蛋疼。另外坐标的顶点是位于屏幕的左上角。

1、根据导弹的运动速度矢量来调整导弹头的方向

2、导弹的速度矢量为x和y方向的矢量和,根据反三角函数来计算出导弹与屏幕坐标y轴的夹角

3、要特别注意当moveVy为0的情况,不考虑这个会导致计算反三角的时候分母为零而因溢出而报错,以及moveVy小于0的情况,不考虑这个会使得方向刚好会想法。

最终的代码为:

sing UnityEngine;
using System.Collections;
using UnityEngine.UI;  

public class AITrackAdvanced : MonoBehaviour {
    public Image target;
    public float target_moveSpeed;
    public float MIN_trackingRate;//最小的追踪向量改变率
    public float MIN_TrackingDis;
    public float MAX_trackingVel;
    public float moveVx;//x方向的速度
    public float moveVy;//y方向的速度
    // Use this for initialization
    void Start () {  

    }  

    // Update is called once per frame
    void Update () {
        Debug.Log((Mathf.Atan(moveVx / moveVy) * (-180 / Mathf.PI)));  

       //  LookAtTarget();
      //  this.transform.position += new Vector3(moveVx * Time.deltaTime, moveVy * Time.deltaTime, 0);
       MoveTarget();
       Track_AIAdvanced();
       CheckMoveBoundary();
    }
    void LookAtTarget()
    {
        float zAngles;
        if(moveVy==0)
        {
            zAngles = moveVx >= 0 ? -90 : 90;
        }
        zAngles = Mathf.Atan(moveVx / moveVy) * (-180 / Mathf.PI);
       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;
    }
    /// <summary>
    /// 通过键盘来控制移动目标
    /// </summary>
    void MoveTarget()
    {
        float x = Input.GetAxis("Horizontal") * 100;
        float y = Input.GetAxis("Vertical") * 100;
        //如果超出屏幕范围则让它出现在另一面
        target.transform.Translate(x * Time.deltaTime * target_moveSpeed, y * Time.deltaTime * target_moveSpeed, 0);
        if (target.transform.position.x >= Screen.width)
        {
            //使用了Image的target.rectTransform.lossyScale.x来表示显示的图片宽度
            target.transform.position = new Vector3(-target.rectTransform.lossyScale.x, target.transform.position.y, 0);
        }
        else if (target.transform.position.x < -target.rectTransform.lossyScale.x)
        {
            target.transform.position = new Vector3(Screen.width, target.transform.position.y, 0);
        }
        if (target.transform.position.y >= Screen.height)
        {
            target.transform.position = new Vector3(target.transform.position.x, -target.rectTransform.lossyScale.y, 0);
        }
        else if (target.transform.position.y < -target.rectTransform.lossyScale.y)
        {
            target.transform.position = new Vector3(target.transform.position.x, Screen.height, 0);
        }
    }
    /// <summary>
    /// 追踪算法
    /// </summary>
    void Track_AIAdvanced()
    {
        //计算与追踪目标的方向向量
        float vx = target.transform.position.x - this.transform.position.x;
        float vy = target.transform.position.y - this.transform.position.y;  

        float length = PointDistance_2D(vx, vy);
        //如果达到距离就追踪
        if(length<MIN_TrackingDis)
        {
            vx = MIN_trackingRate * vx / length;
            vy = MIN_trackingRate * vy / length;
            moveVx += vx;
            moveVy += vy;  

            //增加一点扰动
            if(Random.Range(1,10)==1)
            {
                vx = Random.Range(-1, 1);
                vy = Random.Range(-1, 1);
                moveVx += vx;
                moveVy += vy;
            }
            length = PointDistance_2D(moveVx,moveVy);  

            //如果导弹飞的速度太快就让它慢下来
            if(length>MAX_trackingVel)
            {
               //让它慢下来
                moveVx *= 0.75f;
                moveVy *= 0.75f;
            }  

        }
         //如果不在追踪范围内,随机运动
        else
        {
           if(Random.Range(1,10)==1)
            {
                vx= Random.Range(-2, 2);
                vy = Random.Range(-2, 2);
                moveVx += vx;
                moveVy += vy;
            }
            length = PointDistance_2D(moveVx, moveVy);  

            //如果导弹飞的速度太快就让它慢下来
            if (length > MAX_trackingVel)
            {
                //让它慢下来
                moveVx *= 0.75f;
                moveVy *= 0.75f;
            }
        }  

        this.transform.position += new Vector3(moveVx * Time.deltaTime, moveVy * Time.deltaTime, 0);
    }
    /// <summary>
    /// 计算从零点到这个点的距离
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    float PointDistance_2D(float x,float y)
    {
        //使用了泰勒展开式来计算,有3.5%的误差,直接使用开方计算会比较慢,但是测试了我的电脑好像没有什么变化可能是数据量不大体现不出来
        /*x = Mathf.Abs(x);
        y = Mathf.Abs(y);
        float mn = Mathf.Min(x, y);//获取x,y中最小的数
        float result = x + y - (mn / 2) - (mn / 4) + (mn / 8);*/  

        float result = Mathf.Sqrt(x * x + y * y);
        return result;
    }  

    void CheckMoveBoundary()
    {
        //检测是否超出了边界
        if (this.transform.position.x >= Screen.width)
        {
            this.transform.position = new Vector3(-this.GetComponent<Image>().rectTransform.lossyScale.x, 0, 0);
        }
        else if (this.transform.position.x < -this.GetComponent<Image>().rectTransform.lossyScale.x)
        {
            this.transform.position = new Vector3(Screen.width, this.transform.position.y, 0);
        }
        if (this.transform.position.y >= Screen.height)
        {
            this.transform.position = new Vector3(this.transform.position.x, -this.GetComponent<Image>().rectTransform.lossyScale.y, 0);
        }
        else if (this.transform.position.y < -this.GetComponent<Image>().rectTransform.lossyScale.y)
        {
            this.transform.position = new Vector3(this.transform.position.x, Screen.height, 0);
        }
    }
}

  最后附上工程的下载地址,里面是我用Unity5.1.1写的如图的演示程序,还包括之前两篇文章中的演示程序。点击打开链接

时间: 2024-10-19 01:33:25

Unity人工智能学习—确定性AI算法之追踪算法二的相关文章

AI 经典书单 | 人工智能学习该读哪些书

转载 2018年01月16日 00:00:00 人工智能相关岗位中,涉及到的内容包含: 算法.深度学习.机器学习.自然语言处理.数据结构.Tensorflow.Python .数据挖掘.搜索开发.神经网络.视觉度量.图像识别.语音识别.推荐系统.系统算法.图像算法.数据分析.概率编程.计算机数学.数据仓库.建模等关键词,基本涵盖了现阶段人工智能细分领域的人才结构. 将上面的岗位涉及到的知识和技术划类,就形成了今天的五份书单: 1人工智能科普类:人工智能科普.人工智能哲学 <智能的本质>斯坦福.

机器学习与人工智能学习资源导引

机器学习与人工智能学习资源导引 TopLanguage(https://groups.google.com/group/pongba/) 我经常在 TopLanguage 讨论组上推荐一些书籍,也经常问里面的牛人们搜罗一些有关的资料,人工智能.机器学习.自然语言处理.知识发现(特别地,数据挖掘).信息检索 这些无疑是 CS 领域最好玩的分支了(也是互相紧密联系的),这里将最近有关机器学习和人工智能相关的一些学习资源归一个类: 首先是两个非常棒的 Wikipedia 条目,我也算是 wikiped

人工智能学习线路

学习人工智能有段时间了,总结了一下人工智能的学习历程和课程表,希望对想学习的朋友有所帮助.期间也买了很多资料.可以分享给大家. 阶段一:数学基础 1.数据分析 常数e 导数 梯度 Taylor gini系数 信息熵与组合数 2.概率论 概率论基础 古典模型 常见概率分布 大数定理和中心极限定理 协方差(矩阵)和相关系数 最大似然估计和最大后验估计 3.线性代数及矩阵 线性空间及线性变换 矩阵的基本概念 状态转移矩阵 特征向量 矩阵的相关乘法 矩阵的QR分解 对称矩阵.正交矩阵.正定矩阵 矩阵的S

唐宇迪-人工智能学习路线(下篇)

唐宇迪:51CTO微职位讲师,计算机博士,人工智能专家 内容梗概:介绍人工智能学习步骤和知识框架.人工智能的学习可以拆分为7步,此为4-7步:下篇. 第4步:深度学习 1)深度学习概述 终于说到深度学习了,都需要学什么呢?深度学习可以说是当下最好用的算法了,各个领域都能吃得开.其实最核心的还是在计算机视觉和自然语言处理中,因为神经网络算法更适用于图像和文本数据. 主要需要掌握的就是算法和框架了,算法就是CNN,RNN这些经典网络模型,框架就是实战的工具了例如tenorflow,Pytorch等,

产品学习之个性化推荐和热度算法详解

今日头条的走红带动了"个性化推荐"的概念,自此之后,内容型的产品,个性化算法就逐渐从卖点变为标配. 伴随着"机器学习","大数据"之类的热词和概念,产品的档次瞬间提高了很多.而各种推荐算法绝不仅仅是研发自己的任务,作为产品经理,必须深入到算法内部,参与算法的设计,以及结合内容对算法不断"调教",才能让产品的推荐算法不断完善,最终与自己的内容双剑合璧. 本文以新闻产品为例,结合了我之前产品从零积累用户的经验,整理了作为PM需要了

jvm学习笔记一(垃圾回收算法)

一:垃圾回收机制的原因 java中,当没有对象引用指向原先分配给某个对象的内存时候,该内存就成为了垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃.当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用.事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片.由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片.碎片是分配给对象的内存块之间的空闲内存洞.碎片整理将所占用的堆内存移到堆

唐宇迪-人工智能学习路线(上篇)

唐宇迪:51CTO微职位讲师,计算机博士,人工智能专家 内容梗概:介绍人工智能学习步骤和知识框架.人工智能的学习可以拆分为7步,此为1-3步:上篇. 第1步:必备基础技能 要学人工智能(数据科学)这行还是需要一些基本功的,最基础也是最核心的就是Python和数学了!这两兄弟入门起来并不难,先掌握基础的边用边学也是可以的! 1)必备Python基础 如果对Python不熟悉的同学们,建议先看一下我的Python入门视频课程,可以快速入门!免费学习链接:https://edu.51cto.com/c

javascript学习5-练习之2冒泡排序算法

复习冒泡排序算法,同时自己也写了一个排序算法. 实现效果: 1.自己的算法思想: 数组中数据取第一个为默认最小,依次和后面每个数据比较,只要有比其小的就交换直至找出最小的. 然后将第二个数据与其后面所有数据比较,找出最小,依次重复 2.冒泡排序算法思想: 数据从最低端到最高端为 a[n] ......a[0] 第一轮:将a[0]与a[1]比较,高者上,然后依次比较a[1]和a[2]....a[n-1]和a[n]每次将大的往上冒 第二轮: 将a[0]与a[1]比较,高者上,然后依次比较a[1]和a

Dynamic CRM 2013学习笔记(七)追踪、监控及性能优化

本文将介绍CRM的三个内容追踪.监控及性能优化.追踪是CRM里一个很有用的功能,它能为我们的CRM调试或解决错误.警告提供有价值的信息:我们可以用window的性能监控工具来了解CRM的性能状况:最后就是对CRM及其DB进行性能调整以让CRM达到最佳状态.   一.追踪 有二种追踪方式,一种是部署级,这种方式追踪所有的CRM 服务器上的角色.服务,默认情况,log文件在C:\crmdrop\logs:另一种是服务器级追踪,这种方式只追踪当前机器上运行的服务器角色.服务.默认情况,log文件在C: