Движение бота по ключевым точкам

Например, есть некий участок или помещение, который охраняется. Пока охранник не заметил игрока, он должен ходить по ключевым точкам, при этом точек множество и достигнув последней, он снова должен возвращаться к первой/стартовой позиции. Вроде как в игре Hitman, где основная задача игрока, вычислить ключевые позиции ботов, по которым они перемещаются. Здесь мы сделаем нечто подобное, простой вариант, без учета анимаций бота, так как это уже индивидуальные настройки, у нас задача заставить объект ходить по точкам и переключаться на игрока, если он подходит слишком близко.


Перед тем как продолжить, необходимо создать карту для навигации и поиска пути. Сделать это не сложно, подробнее читайте здесь. Далее, чтобы боты знали где в данный момент находится игрок, мы сделаем небольшой скрипт, который будет искать игрока. Ботов может быть много, все они будут обращаться к одной переменной.

Поиск игрока, скрипт PlayerInfo:

using UnityEngine;
using System.Collections;

public class PlayerInfo : MonoBehaviour {

	public static Transform player;

	void Start()
	{
		FindPlayer();
	}

	public static void FindPlayer() 
	{
		player = GameObject.FindGameObjectWithTag("Player").transform;
	}
}

Итак, на старте сцены игрока нашли.

Теперь, сделаем для бота ключевые точки, это обычные объекты. Размещаем их в нужных местах на карте навигации. Вешаем на бота скрипт BotWalk:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(NavMeshAgent))]

public class BotWalk : MonoBehaviour {

	public int activeDistance = 10;
	public Transform[] wayPoints;
	public float stoppingDistance = 5;
	public float timeWait = 3;
	public float rotationSpeed = 5;
	public Transform defLook;
	private NavMeshAgent agent;
	private Vector3 target;
	private float curTimeout;
	private int wayCount;
	private bool isTarget;

	void Start () 
	{
		agent = GetComponent<NavMeshAgent>();
	}

	void SetRotation(Vector3 lookAt)
	{
		Vector3 lookPos = lookAt - transform.position;
		lookPos.y = 0;
		Quaternion rotation = Quaternion.LookRotation(lookPos);
		transform.rotation = Quaternion.Lerp(transform.rotation, rotation, rotationSpeed * Time.deltaTime);
	}

	void Update () 
	{
		target = PlayerInfo.player.position;
		float dis = Vector3.Distance (transform.position, PlayerInfo.player.position);
		if(dis < activeDistance)
		{
			isTarget = true;
		}
		
		if(wayPoints.Length >= 2 && !isTarget)
		{
			agent.stoppingDistance = 0;
			agent.SetDestination(wayPoints[wayCount].position);
			if(!agent.hasPath)
			{
				SetRotation(defLook.position);
				curTimeout += Time.deltaTime;
				if(curTimeout > timeWait){curTimeout = 0; if(wayCount < wayPoints.Length-1) wayCount++; else wayCount = 0;}
			}
		}
		else if(wayPoints.Length == 0 || isTarget)
		{
			agent.stoppingDistance = stoppingDistance;
			agent.SetDestination(target);
			if(agent.velocity == Vector3.zero) SetRotation(target);
		}

	}
}

Переключение на игрока, если он зашел в радиус activeDistance. Дистанция до игрока stoppingDistance, в режиме преследования. Ключевые точки мы помещаем в массив wayPoints. Время ожидания, послед достижения одной из точек timeWait. Точка на которую будет смотреть бот, в момент ожидания defLook. Движение по точкам возможно только если их две или более.

Комментариев 1

Офлайн
SkyAngel 27 ноября 2016
Красиво написано! Спасибо автору(ам) за столь чудесный пример!
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика