Страницы

четверг, 19 декабря 2019 г.

Процедурное создание уровней в Unity. Часть 5-1. Создание виртуальной Солнечной системы на основе XML-файла. Скрипт движения планет

Теперь мы знаем, как читать XML-файл из папки Resources. Основываясь на этих знаниях, мы можем смоделировать создание виртуальной Солнечной системы из XML-файла. Запишем в файл всю информацию, связанную с планетами (например, размер, орбитальная скорость и т. д.) и затем загрузим ее, чтобы создать простую визуализацию этих данных в Unity.
Необходимо выполнить следующие действия:
  • создать префаб для планеты, который будет включать переменные, которые могут быть изменены, такие как размер или орбитальная скорость.
  • загрузить и считать XML-файл, содержащий информацию обо всех этих планетах.
  • создать экземпляры планет в Unity и моделировать их движение.
Начнем:
  • Создайте новую сцену (File | New Scene).
  • Сохраните ее с названием solarSystem (File | Save Scene As) или другим названием на ваш выбор. Откройте ее (File | Open Scene).
  • Создайте новый объект sphere и назовите его sun.
  • Установите координаты положения сферы position (0,0,0) и масштаб scale (110, 110, 100).
Сейчас нам нужен материал для Солнца.
  • Создайте новый материал (Create | Material). Назовите его sunColor.
  • Выберите его.
  • Кликните на белый квадрат справа от надписи Albedo.

Рис. 20. Изменение материала для Солнца
Откроется окно выбора цвета
Рис. 21. Выбор цвета для Солнца
Выберем желтый цвет.
Выделите объект sun и примените к нему новый материал.
Установите материалу атрибут шейдер - Legacy Shader | Self-Illumin | Diffuse.

Рис. 22. Установка шейдера

Рис. 23. Так выглядит Солнце после применения материала
Сейчас у нас есть наше Солнце в центре сцены, и дальше мы создадим префаб под названием planet, который будет использоваться для создания экземпляров всех планет, включенных в XML-файл.
  • Создайте новую сферу и назовите ее planet.
  • Установите ее позицию в (150, 0, 150) и масштаб (1, 1, 1).
  • Создайте новый 3D Text object (GameObject | 3D Object | 3D Text), назовите его label.
  • Перетащите в иерархии объект label на объект planet, чтобы сделать его потомком планеты.
Рис. 24. Объекты в иерархии
Установите координаты положения надписи (0, 1.76, 0) и текст «Земля». Свойство Anchor – Middle Center.
Рис. 25. Настройка свойств надписи
Установим движение планеты с помощью простого скрипта.
Создайте новый C# скрипт и назовите его Planet.
Добавьте в начало класса следующий код:
float rotationalSpeed = 10f;
float orbitalSpeed = 0.20f;
float orbitalAngle = 0.0f;
float angle = 0.0f;
float orbitalRotationalSpeed = 20;
float distanceToSun = 150;
GameObject sun;
Мы устанавливаем параметры для планеты, включая скорость вращения (скорость, с которой планета вращается вокруг своей оси), орбитальную скорость (скорость, с которой планета движется вокруг Солнца), орбитальный угол (угол поворота вокруг Солнца), угол (угол поворота вокруг оси планеты), орбитальную скорость вращения (скорость, с которой планета вращается вокруг Солнца) и расстояние до Солнца.
Мы также объявляем GameObject под названием sun, который будет использоваться в качестве центра вращения планет.
Изменим функцию Start, добавив в нее код:
void Start()
{
    sun = GameObject.Find("sun");
    transform.position = new Vector3(distanceToSun, 0, distanceToSun);
}
Мы создали ссылку на объект sun и установили временное положение для планеты.
Поработаем над вращательным движением планет; оно включает в себя вращение вокруг оси планеты, а также вращение вокруг Солнца (т.е. орбитальное вращение).
Добавьте код в метод Update:
void Update()
{
    transform.Rotate(Vector3.up, rotationalSpeed * Time.deltaTime, Space.World);
    float tempx, tempy, tempz;
    orbitalAngle += Time.deltaTime * orbitalSpeed;
    tempx = sun.transform.position.x + distanceToSun * Mathf.Cos(orbitalAngle);
    tempz = sun.transform.position.z + distanceToSun * Mathf.Sin(orbitalAngle);
    tempy = sun.transform.position.y;
    transform.position = new Vector3(tempx, transform.position.y, tempz);
}
Мы вращаем планету вокруг ее оси Y.
Затем вращаем планету вокруг Солнца, используя ее расстояние до Солнца вместе с синусом и косинусом угла, определяемого ее положением по отношению к Солнцу.

❓❔❓ 
Если вы рассматриваете окружность, ее центр O и любую точку на этой окружности M, координаты этой точки M можно определить по радиусу окружности R и соответствующему углу, определяемому положением точки M на окружности.
y = R*sin(угол) x = R*cos(угол)
Мы используем три временные переменные tempx, tempy и tempz для хранения положения планеты и создания соответствующего вектора.

Сохраните сценарий и прикрепите его к объекту под названием planet.
После этого запустите сцену.
Вы должны увидеть объект планеты, вращающийся вокруг Солнца в виде сцены
Обратите внимание, что вы можете выбрать объект планета, а затем сфокусироваться на нем с помощью SHIFT +F.

Рис. 26. Земля, вращающаяся вокруг Солнца (масштаб изменен)
По заданному масштабу Земля получится очень мелкая, поэтому я увеличил немного ее масштаб (scale) для иллюстрации. Это дальше от реальности, но зато лучше видно (от studhelper). 

Все работает, но может быть трудно найти планету, которая вращается вокруг Солнца. Создадим след, который показывает полную орбиту планеты. Для этого мы будем использовать LineRenderer; они часто применяются для рисования линий в Unity. В нашем случае, когда мы хотим создать эллипс (или круг, в нашем случае, чтобы упростить код), мы создадим последовательность бесконечно малых линий, которые, нарисованные вместе, будут восприниматься как эллипс (или круг).
Добавьте объявления переменных в начало класса:
private Color c1 = Color.blue;
private int lengthOfLineRenderer = 100;
Здесь мы определяем цвет линий и их количество. Всего будем рисовать 100 линий, но можно и больше.
Добавьте в класс следующую функцию (устаревший код выделен курсивом и цветом – studhelper):
void drawOrbit()
{
    LineRenderer lineRenderer = gameObject.AddComponent<LineRenderer>();
    lineRenderer.material = new Material(Shader.Find("Mobile/Particles/Additive"));
    
    lineRenderer.SetColors(c1, c1);
    lineRenderer.SetWidth(1.0F, 1.0F);
    lineRenderer.SetVertexCount(lengthOfLineRenderer + 1);

}
Три последних строки устарели, перепишем их.
lineRenderer.startColor = c1;
lineRenderer.endColor = c1;
lineRenderer.startWidth = 1.0F;
lineRenderer.endWidth = 1.0F;
lineRenderer.positionCount = lengthOfLineRenderer + 1;
Мы объявляем новый компонент LineRenderer.
Затем устанавливаем его материал с помощью шейдера Mobile / Particles / Additive, чтобы придать линиям характерный вид.

❓❔❓ 
Что делает шейдер. В двух словах, шейдер позволяет преобразовать внешний вид объектов, изменяя способ восприятия их цвета и добавляя специальные эффекты.


  • Мы устанавливаем начальный и конечный цвет для этого полигона (т. е. последовательности линий), чтобы линия была синей.
  • Затем мы устанавливаем начальную и конечную ширину линии.
  • И последнее, но не менее важное: мы устанавливаем количество вершин (число позиций), которые будут использоваться для следа планеты.

Чтобы нарисовать линию, мы определим точки через равные промежутки на круге, который соответствует орбите планеты, а затем соединим эти точки, чтобы создать иллюзию круга. Эти точки определяются радиусом и углом; угол основан на полной длине окружности в радианах, разделенной на количество точек, так что они включены через равные интервалы.
Добавьте следующий код в конце функции drawOrbit:
int i = 0;
while (i <= lengthOfLineRenderer)
{
   float unitAngle = (float)(2 * 3.14) / lengthOfLineRenderer;
   float currentAngle = (float)unitAngle * i;
   Vector3 pos = new Vector3(distanceToSun * Mathf.Cos(currentAngle), 0,
   distanceToSun * Mathf.Sin(currentAngle));
    lineRenderer.SetPosition(i, pos);
    i++;
}
Мы создаем цикл со счетчиком, который начинается с 0 и увеличивается до 100 (т.е. до значения переменной lenghtOfLineRenderer).

Затем мы определяем для каждой точки угол и положение. Чтобы создать то, что будет выглядеть как круг, мы делим 360 градусов (т.е. 360*Пи/180 = 2*3,14 радиана) на 100, чтобы найти угол между каждой из этих точек

После этого угол (назовем его unitAngle) умножим на значение счетчика (номер точки); например, первая точка (номер 0) будет под углом unitAngle*0 (0.0628*0), вторая точка будет под углом unitAngle*1 (0.0628*1), и так далее.

Затем мы используем функцию SetPosition; эта функция определяет положение каждой точки, которая составляет многоугольник (или последовательность линий). Первый параметр - это индекс, а второй параметр - фактическое положение этой точки. Индекс будет увеличиваться от 0 до значения переменной lenghtOfLinerenderer; положение точки определяется на основе точки, вокруг которой вращается планета, - Солнца, а также ее относительного угла вдоль орбитального пути.
Добавьте вызов drawOrbit() в функцию Start.
drawOrbit();
Наконец, чтобы вы могли видеть сцену более четко, измените положение основной камеры (Main Camera) на (0, 263, 0) и его поворот на (90, 0, 0).
Результаты запуска сцены:

Рис. 27. Орбита планеты из вида сцены
Рис. 28. Орбита планеты из вида игры
Во время запущенной игры выберите объект планету и посмотрите в Инспектор. Вы увидите компонент Line Renderer, который включает серию точек, определенных нами в скрипте.

Рис. 29. Объект Line Renderer во время запуска игры
Содержание
Часть 4. Использование XML-файлов для создания контента
Часть 5-2. Создание виртуальной Солнечной системы на основе XML-файла. Работа с файлом