Unity人工智能学习 — 确定性AI算法之追踪算法
作者:风晓融冰 原文:http://www.taidous.com/forum.php?mod=viewthread&tid=28412
随机运动虽然完全不可预测,但它相当无趣,因为它始终以相同的随机方式运行。接下来要学习的算法能够根据具体环境做出不同响应,这里以追踪算法为例进行介绍。追踪AI会考虑跟踪目标的位置,然后调整AI对象的轨迹,使其朝着被追踪的对象移动。
追踪方式可以是将方向矢量直接指向目标,也可以采用更真实的模型,让物体像导弹那样行动。本文主要介绍第一种方式——直接矢量追踪,其效果如下描述:通过键盘方向键控制幽灵,蚊子会追踪幽灵。同时,做了一些界面处理,当蚊子或者幽灵运动超出屏幕范围时,它们会出现在屏幕的另一边,而不是消失在屏幕上。
追踪算法代码实现
以下是实现追踪算法的代码:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AITrack : MonoBehaviour {
public Image target;
public float moveSpeed; // 追踪目标移动速度
public float targetSpeed; // 追踪速度
public float target_x; // 追踪移动的单位量
public float target_y;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
MoveTarget();
Track_AI();
}
void Track_AI()
{
// x方向的追踪
if(target.transform.position.x > this.transform.position.x)
{
this.transform.position += new Vector3(target_x, 0, 0) * targetSpeed;
}
else if(target.transform.position.x < this.transform.position.x)
{
this.transform.position -= new Vector3(target_x, 0, 0) * targetSpeed;
}
// y方向的追踪
if(target.transform.position.y > this.transform.position.y)
{
this.transform.position += new Vector3(0, target_y, 0) * targetSpeed;
}
else if(target.transform.position.y < this.transform.position.y)
{
this.transform.position -= new Vector3(0, target_y, 0) * targetSpeed;
}
// 检测是否超出了边界
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);
}
}
void MoveTarget()
{
float x = Input.GetAxis("Horizontal") * 100;
float y = Input.GetAxis("Vertical") * 100;
target.transform.Translate(x * Time.deltaTime * moveSpeed, y * Time.deltaTime * 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);
}
}
}
读取Sprite制作动画的代码
本例中还使用了一段读取Sprite制作动画的代码,如下:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
public enum AnimPalyStyle : byte
{
Once, Loop, Poop
}
public class SpriteAnim : MonoBehaviour {
public Image image;
private List<Sprite> m_sprites = new List<Sprite>();
public string path;
public float playSpeed;
public AnimPalyStyle playStyle;
public int MaxFrame;
// Use this for initialization
void Start () {
}
void OnEnable()
{
StartCoroutine(LoadSprites(MaxFrame, path));
}
// Update is called once per frame
void Update () {
}
IEnumerator LoadSprites(int max, string name)
{
Sprite tempSprite;
int j = 0;
int nameLenght = name.Length;
for (; j < max; j++)
{
name = name.Substring(0, nameLenght - j.ToString().Length + 1) + j;
tempSprite = Resources.Load<Sprite>(name);
yield return new WaitForSeconds(playSpeed);
image.sprite = tempSprite;
if (!m_sprites.Contains(tempSprite))
{
m_sprites.Add(tempSprite);
}
if (playStyle == AnimPalyStyle.Once)
{
this.enabled = false;
}
}
j = 0;
if (playStyle == AnimPalyStyle.Loop)
{
for (; j < max; j++)
{
yield return new WaitForSeconds(playSpeed);
image.sprite = m_sprites[j];
if (j == max - 1)
{
j = 0;
}
}
}
else if (playStyle == AnimPalyStyle.Poop)
{
while (true)
{
while (j < max)
{
if (j == -1) j = 0;
yield return new WaitForSeconds(playSpeed);
image.sprite = m_sprites[j];
j++;
}
while (j > -1)
{
if (j == max) j = max - 1;
yield return new WaitForSeconds(playSpeed);
image.sprite = m_sprites[j];
j--;
}
}
}
}
}
工程信息
本例使用的是Unity 5.1.1版本,工程下载地址:http://www.taidous.com/forum.php?mod=viewthread&tid=28412。