关闭

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

标签: Unity人工智能算法
2981人阅读 评论(2) 收藏 举报
分类:

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

上一篇讲到了追踪算法的比较简单的形式,看上去比较假,因为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的情况,不考虑这个会使得方向刚好会想法。

最终的代码为:

using 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写的如图的演示程序,还包括之前两篇文章中的演示程序。点击打开链接


0
0
查看评论

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

前面的追踪都能很好的解决大部分的问题,但是人工智能的宗旨是模拟实现更为真实更为智能的智能体。同样,一个简单的追踪算法它也是有很多优化为更智能的需求。这一篇是追踪算法里面的拦截追踪,效果图如图所示: 这个就不在是前面简单生硬的尾随而至的追踪了,导弹是根据飞机的飞行速度来提前拦截飞机,这里有一个追...
  • zhangxiao13627093203
  • zhangxiao13627093203
  • 2015-10-09 11:47
  • 1683

Unity人工智能学习—基本模式控制

  • 2015-08-16 22:59
  • 44.06MB
  • 下载

Unity3D研究院之游戏开发中的人工智能AI

人工智能这个东西在游戏中是非常重要的,人工智能说简单了就是根据随机的数字让敌人执行一些动作或逻辑,说难了TA需要一个非常复杂的算法,本文我主要说说Unity3D中人工智能的脚本如何来编写。         首先你应该搞清楚的一点AI脚本属于一个工具类脚本...
  • mango9126
  • mango9126
  • 2016-12-16 14:38
  • 939

自己进化的Unity人工智能(二)

第一章的地址:http://blog.csdn.net/m0_37283423/article/details/78333623 因为上次发的有人私信我说看不懂,让我详细讲下,那这篇就详细剖析一下; 因为游戏中的神经网络(以后用BP代替)不是识别用途,没有一个样本值,我们只需要阈值来判断行为的大...
  • m0_37283423
  • m0_37283423
  • 2017-10-24 19:51
  • 590

Unity3D人工智能编程源代码

  • 2016-09-04 14:36
  • 48B
  • 下载

Unity人工智能学习—躲避规则障碍一

第一部分:效果预览先上效果图。这一部分将要讲的是智能躲避规则的障碍物。其实,这是最终现实效果,在算法中实际上使用到了 一个隐藏的碰撞检测盒子,这个盒子是从智能体延伸出的。如图所示:保持红色长方形区域不被碰撞就可以躲避障碍物了。检测盒的宽度等于智能体的包围半径 它的长度正比于智能体...
  • zhangxiao13627093203
  • zhangxiao13627093203
  • 2015-11-13 10:52
  • 2657

AI大行其道,你准备好了吗?—谨送给徘徊于转行AI的程序员

前言  近年来,随着 Google 的 AlphaGo 打败韩国围棋棋手李世乭之后,机器学习尤其是深度学习的热潮席卷了整个IT界。所有的互联网公司,尤其是 Google 微软,百度,腾讯等巨头,无不在布局人工智能技术和市场。百度,腾讯,阿里巴巴,京东,等互联网巨头甚至都在美国硅谷大肆高薪挖掘人工智能...
  • u013709270
  • u013709270
  • 2017-07-09 16:13
  • 23924

unity3d AI 学习--个体行为操控(1)--具体行为类(2)

摘自《Unity3D人工智能编程精粹》 以下都是继承Steering类的,直接上代码了: Pursuit(追逐):using UnityEngine; using System.Collections; public class SteeringForPursuit : Ste...
  • qq_28221881
  • qq_28221881
  • 2016-10-18 10:04
  • 1353

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

在追踪算法三中已经提到了它的缺陷之处:到达目标点的时候并不会马上停下来,而是不停的来回穿梭在目标点。这一篇其实就是第三篇优化这个缺陷的算法。它的效果图如图所示: 它的核心算法代码如下: Vector2 Track_AIAdvancedArrive() { Vector2 ...
  • zhangxiao13627093203
  • zhangxiao13627093203
  • 2015-10-09 11:24
  • 1132

游戏瞄准的一个AI算法

在很多飞行射击类游戏里,都有敌人向玩家自动瞄准并开火的功能。在这里本人 用unity3d引擎新版本的2D系统来实现这个功能。 首先,让我们了解一下原理的理论知识。我们可以把敌人和玩家放到一个坐标系 中,敌人是坐标是的原点((0,0)点),玩家是在这个坐标系中的一点。然后把二 者在坐标系中构建...
  • qq_17540945
  • qq_17540945
  • 2015-03-02 11:21
  • 644
    个人资料
    • 访问:65244次
    • 积分:999
    • 等级:
    • 排名:千里之外
    • 原创:34篇
    • 转载:0篇
    • 译文:0篇
    • 评论:30条
    文章分类
    博客专栏