您的位置:首页 > 移动开发 > Unity3D

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

2015-09-10 09:42 731 查看
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)有什么不一样。我在反追踪代码上面还加了一个距离的判断,也就是当目标和 飞机的距离小于预设的追踪距离的时候就开始追踪,它的效果图如图所示
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: