Путь планеты

Готовый проект урока, скачать.

Обычно, в играх планетарного масштаба, помимо самих планет, на экране отображается вспомогательная информация, такая как орбита или информация о самих планетах.

Вывести такую информацию на экран довольно просто. В юнити есть как минимум 3 разных способа:

1) LineRenderer/TrailRenderer компоненты, первый компонент позволяет рисовать линию задавая точки её изгиба, а второй сам рисует линию по координатам, который прошел объект на который этот компонент был присоединён. Минус в том, что такие линии могут быть только трёхмерными, что не подходит для отображения в качестве элемента GUI. Плюс в том, что очень просто рисовать линии таким образом.

2) Graphics позволяет рисовать линию как сетку прямоугольника вручную, минус в том, что надо вычислять позицию каждой вершины прямоугольника изображающего линию. Плюс в том, что этот способ даёт максимальный уровень управления внешним видом результата.

3) GL позволяет обратиться напрямую к возможностям OpenGl и нарисовать линию. Минус в том, что линия всегда будет одной ширины, плюс в том, что это несколько проще в сравнении с Graphics.

Последний вариант разберём более подробно.

using UnityEngine; using System.Collections; using System.Collections.Generic; [RequireComponent(typeof(Camera))] public class DrawPath : MonoBehaviour { // Цель, чей след рисуем public Transform target; // Материал линии public Material material; // Длина "хвоста" цели в попугаях public int trailLength = 5000; private new Camera camera; // Список всех прошлых позиций цели private List<Vector3> vertices = new List<Vector3>(); void Start () { camera = GetComponent<Camera>(); } void Update () { // Сохраняем текущую позицию цели vertices.Add(target.position); // Ограничиваем длину "хвоста" if (vertices.Count > trailLength) vertices.RemoveAt(0); } // Специальная функция для рисования через GL, // чтобы она сработала надо прикреплять компонент // к объекту камеры. void OnPostRender() { if (!material) { Debug.LogError("Please Assign a material on the inspector"); return; } // Это особенность работы OpenGL // Примите как данность, что для // изменения матрицы проекции // её надо сначала сохранить PushMatrix // командой, и восстановить // PopMatrix командой GL.PushMatrix(); // Указываем какой материал должен сработать material.SetPass(0); // Устанавливаем матрицу проекции без // перспективного искажения и получаем // "плоский" мир для всего, что будет // нарисовано далее GL.LoadOrtho(); // Начинаем рисовать линии, это означает // что надо передать по две точки, а в результате // будет нарисована одна линия GL.Begin(GL.LINES); GL.Color(Color.red); for (int i = 1; i < vertices.Count; i++) { // Мы запомнили мировые координаты точки, // преобразуем их в экранные. Vector3 pos = camera.WorldToScreenPoint(vertices[i - 1]); // И вгоняем их в диапазон от 0 до 1 // т.к. OpenGl принимает экранные координаты // в таком виде. pos.x /= Screen.width; pos.y /= Screen.height; // И передаём точку в GPU GL.Vertex3(pos.x, pos.y, 0); // Выше мы начало линии вычислили и передали, // ниже вычисляем и передаём конец pos = camera.WorldToScreenPoint(vertices[i]); pos.x /= Screen.width; pos.y /= Screen.height; GL.Vertex3(pos.x, pos.y, 0); } // Следующими инструкциями завершаем рисование GL.End(); GL.PopMatrix(); } }

Этот компонент надо прикрепить к той камере, на которой мы хотим видеть рисуемые данные, задать цель слежения и материал линии.

Но что если надо не только нарисовать путь, но и вывести некоторый текст.

using UnityEngine; using System.Collections; [RequireComponent(typeof(Camera))] public class DrawHighlight : MonoBehaviour { public Transform highlightTarget; public Material material; public float marginSize = 0.05f; public float underlineSize = 0.20f; public int labelHeight = 20; private new Camera camera; void Start () { camera = GetComponent<Camera>(); } void OnGUI() { // Приводим координаты цели к экранным Vector3 pos = camera.WorldToScreenPoint(highlightTarget.position); // Делаем отступ от позиции цели pos.x += Screen.width * marginSize; pos.y += Screen.height * marginSize + labelHeight; // Вот такая особенность у GUI юнити, что экранные // координаты надо передавать в перевёрнутом виде pos.y = Screen.height - pos.y; GUI.Label( new Rect(pos.x, pos.y, Screen.width * underlineSize, labelHeight) ,"Earth"); } void OnPostRender() { if (!material) { Debug.LogError("Please Assign a material on the inspector"); return; } GL.PushMatrix(); material.SetPass(0); GL.LoadOrtho(); GL.Begin(GL.LINES); GL.Color(Color.red); // Получаем координаты цели Vector3 pos = camera.WorldToScreenPoint(highlightTarget.position); pos.x /= Screen.width; pos.y /= Screen.height; // Рисуем диагональную линию от цели GL.Vertex3(pos.x, pos.y, 0); GL.Vertex3(pos.x + marginSize, pos.y + marginSize, 0); // Подрисовываем горизонтальную линию к диагональной GL.Vertex3(pos.x + marginSize, pos.y + marginSize, 0); GL.Vertex3(pos.x + marginSize + underlineSize, pos.y + marginSize, 0); GL.End(); GL.PopMatrix(); } }

В этом примере мы рисовали текст средствами Unity Legacy GUI, но можно было нарисовать и средствами OpenGL и новой системой GUI. Приведённый выше способ использован только из-за наглядности и простоты.

results matching ""

    No results matching ""