Организация построения юнитов в RTS игре
Речь идет о построении отдельных юнитов в отряд и ориентирование его, относительно указателя. То есть, каждый юнит остается сам по себе, но все они выстраиваются в несколько рядов и каждый ряд/линия разворачивается по направлению вектора указателя. В некоторых стратегиях вы наверняка пользовались возможностью, когда с помощью мышки, можно указать иконкой (в виде стрелки, как правило), как построиться юнитам. Это удобно тем, что войска можно сразу развернуть «лицом» в сторону, откуда ожидается нападение. Таким образом мы получаем столкновение лоб в лоб, и не тратится драгоценное время на разворот отряда.
Итак, для того чтобы всё работало нам нужно подготовить две вещи. Первое, это должна быть создана карта навигации для юнитов, о том как это делается можно прочить здесь. Во-вторых, понадобится еще одна мелочь, надо нарисовать иконку указателя и импортировать ее как спрайт.
На юнитов цепляем скрипт UnitNav, либо измените существующий в соответствии:
Скрипт отвечает за позицию объекта и вращение, когда идет построение в отряд.
Теперь добавим пустой объект на сцену и вешаем еще один скрипт FillEntry:
units - массив юнитов, которые выбраны в данный момент, например, после выделения рамкой. Кстати говоря, этот скрипт можно комбинировать с другим, который мы публиковали ранее. В итоге получится полноценная система управления.
lineCount - из скольких юнитов будет построен один ряд, а количество рядов определяется автоматически, в зависимости от общего числа выбранных единиц.
shift - сдвиг между позициями в отряде.
activeDistance - расстояние между двумя точками. Первая - после нажатия ПКМ. Вторая - текущая позиция курсора, во время удерживания ПКМ. Иначе говоря, если игрок зажимает ПКМ, ему надо передвинуть курсор, после чего появится указатель. Если игрок просто кликает ПКМ то, выполняется команда следования в указанную точке, без построения.
arrow - трансформ спрайта стрелки.
arrowSprite - здесь указываем Sprite Renderer объекта.
Сам спрайт указателя необходимо правильно добавить на сцену, вид должен быть примерно такой:

То есть, картинка должна лежать на плоскости ХZ, а указатель развернут стрелкой по оси Z. Делается это просто, создаем пустой объект, закидываем в него спрайт и разворачиваем относительно осям родителя - всё.
В принципе, можно использовать текущий вариант в игре. Тем не менее, не стоит забывать, что это лишь образец, который можно и нужно улучшать. Например здесь шаблон для отряда создается каждый раз новый, после того как появится указатель, за это отвечает функция SetGrid. Сам по себе, шаблон - это набор пустых объектов, построенных по принципу двумерного массива. Но можно сделать и по другому, создать вручную несколько шаблонов и менять их в зависимости от юнитов, допустим чтобы лучники и мечники, выстраивались на основе разных формаций.
Скачать проект:
Итак, для того чтобы всё работало нам нужно подготовить две вещи. Первое, это должна быть создана карта навигации для юнитов, о том как это делается можно прочить здесь. Во-вторых, понадобится еще одна мелочь, надо нарисовать иконку указателя и импортировать ее как спрайт.
На юнитов цепляем скрипт UnitNav, либо измените существующий в соответствии:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(NavMeshAgent))]
public class UnitNav : MonoBehaviour {
public Vector3 point;
public float stopDistance = 10;
private NavMeshAgent nav;
void Start ()
{
nav = GetComponent<NavMeshAgent>();
point = transform.position;
}
void Update ()
{
nav.SetDestination(point);
if(!nav.hasPath)
{
if(FillEntry.unitLook) transform.rotation = Quaternion.Lerp(transform.rotation, FillEntry.unitRot, 3 * Time.deltaTime);
}
else
{
if(nav.remainingDistance < stopDistance && !FillEntry.unitLook)
{
float speed = nav.speed / (nav.speed - 0.1f);
if(nav.velocity.magnitude < speed) point = transform.position;
}
}
}
}
Скрипт отвечает за позицию объекта и вращение, когда идет построение в отряд.
Теперь добавим пустой объект на сцену и вешаем еще один скрипт FillEntry:
using UnityEngine;
using System.Collections;
public class FillEntry : MonoBehaviour {
public GameObject[] units;
public int lineCount = 5;
public float shift = 5;
public float activeDistance = 1.5f;
public Transform arrow;
public SpriteRenderer arrowSprite;
private GameObject[,] field;
private int line_y;
private Vector2 curHit;
private float rotAngle;
private GameObject grid;
private Vector3 HIT;
private Vector3 curHIT;
public static bool unitLook;
public static Quaternion unitRot;
void Start ()
{
arrowSprite.enabled = false;
unitLook = false;
}
void UnitDestination()
{
int id = 0;
for(int y = 0; y < line_y; y++)
{
for(int x = 0; x < lineCount; x++)
{
if(id < units.Length)
{
units[id].GetComponent<UnitNav>().point = field[x,y].transform.position;
id++;
}
}
}
}
void RotUpdate(Transform target)
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.transform.position.y);
Vector3 curTarget = Camera.main.ScreenToWorldPoint(curScreenPoint);
Vector3 lookPos = curTarget - target.position;
lookPos.y = 0;
Quaternion rotation = Quaternion.LookRotation(lookPos);
target.rotation = rotation;
unitRot = rotation;
}
void ArrowUpdate()
{
if(Input.GetMouseButton(1))
{
float dis = Vector2.Distance(HIT, curHIT);
if(dis > activeDistance)
{
if(!grid)
{
grid = new GameObject();
grid.transform.position = HIT;
arrow.transform.position = HIT;
SetGrid();
}
arrowSprite.enabled = true;
}
if(grid)
{
RotUpdate(arrow);
RotUpdate(grid.transform);
}
}
else
{
arrowSprite.enabled = false;
}
}
void Update ()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
curHIT = hit.point;
if(Input.GetMouseButtonDown(1))
{
Destroy(grid);
unitLook = false;
float a = units.Length;
float b = lineCount;
float tmp = a / b;
line_y = Mathf.CeilToInt(tmp);
field = new GameObject[lineCount, line_y];
HIT = hit.point;
}
else if(Input.GetMouseButtonUp(1))
{
if(grid)
{
unitLook = true;
UnitDestination();
}
else
{
foreach(GameObject u in units)
{
u.GetComponent<UnitNav>().point = hit.point;
}
}
}
}
ArrowUpdate();
}
void SetGrid()
{
float posX = HIT.x - shift * ((float)lineCount / 2);
float posZ = HIT.z + shift * ((float)line_y / 2);
float Xreset = posX;
for(int y = 0; y < line_y; y++)
{
posZ -= shift;
for(int x = 0; x < lineCount; x++)
{
posX += shift;
field[x,y] = new GameObject();
field[x,y].transform.position = new Vector3(posX, 0, posZ);
field[x,y].transform.parent = grid.transform;
}
posX = Xreset;
}
}
}
units - массив юнитов, которые выбраны в данный момент, например, после выделения рамкой. Кстати говоря, этот скрипт можно комбинировать с другим, который мы публиковали ранее. В итоге получится полноценная система управления.
lineCount - из скольких юнитов будет построен один ряд, а количество рядов определяется автоматически, в зависимости от общего числа выбранных единиц.
shift - сдвиг между позициями в отряде.
activeDistance - расстояние между двумя точками. Первая - после нажатия ПКМ. Вторая - текущая позиция курсора, во время удерживания ПКМ. Иначе говоря, если игрок зажимает ПКМ, ему надо передвинуть курсор, после чего появится указатель. Если игрок просто кликает ПКМ то, выполняется команда следования в указанную точке, без построения.
arrow - трансформ спрайта стрелки.
arrowSprite - здесь указываем Sprite Renderer объекта.
Сам спрайт указателя необходимо правильно добавить на сцену, вид должен быть примерно такой:

То есть, картинка должна лежать на плоскости ХZ, а указатель развернут стрелкой по оси Z. Делается это просто, создаем пустой объект, закидываем в него спрайт и разворачиваем относительно осям родителя - всё.
В принципе, можно использовать текущий вариант в игре. Тем не менее, не стоит забывать, что это лишь образец, который можно и нужно улучшать. Например здесь шаблон для отряда создается каждый раз новый, после того как появится указатель, за это отвечает функция SetGrid. Сам по себе, шаблон - это набор пустых объектов, построенных по принципу двумерного массива. Но можно сделать и по другому, создать вручную несколько шаблонов и менять их в зависимости от юнитов, допустим чтобы лучники и мечники, выстраивались на основе разных формаций.
Скачать проект:
Комментариев 4
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.