Основы Unity3D (Unity3D Basics)

Автор: | 20.01.2019

Tags:  Unity Basics  C# Visual Studio

Введение
Интерфейс редактора Unity3D
Панель инструментов
Игровые объекты и их компоненты. Rigidbody
C# скрипты
Префабы
Уничтожение объектов при запуске (runtime)
Создание объектов при запуске (runtime)
Добавление текстуры
Подключение аудио
Создание таймера при помощи скриптов
Движение объектов
Взаимодействие пользователя с приложением
Соединения
Интерфейс пользователя (UI). Переключение сцен
Наследование на примере создания часов
Создание окружающей среды
Полезные ссылки

Введение

Unity3d – один из наиболее известных игровых движков. Он содержит интегрированный редактор проектов, который поддерживает импорт графических и неграфических ресурсов (моделей, в том числе анимированных, текстур, скриптов и т.д.), содержит встроенные ландшафты, использует физический движок Ageia PhysX, обеспечивает смешивание 3D-графики реального времени с потоковым аудио и видео.

Unity3d поддерживает широкий диапазон платформ, включая различные версии Windows  и Android, браузеры: Chrome, Opera и др.

Скачать дистрибутив Unity3d можно по ссылке (там же можете скачать Unity Hub — программу по управлению версиями движка). Для ряда проектов, в основном — где создается ландшафт, дополнительно к Unity3d должны быть установлены ресурсы (Standard assets), скачать можно   здесь.

Программирование графики в Unity3d осуществляется  скриптовым языком C#.

Для работы с исходным кодом на C# должен быть установлен редактор Visual Studio.

Интерфейс редактора Unity3D

После открытия окна  проекта выполните click на Main Camera (в левом верхнем углу). Рассмотрим основные элементы окна

1 – окно иерархии объектов (Hierarchy); 2 – окно сцены (Scene); 3 – окно предварительного просмотра сцены (Camera Preview); 4 – окно инспектора компонентов и их свойств (Inspector); 5,6 – окна проекта (Project) для управления ресурсами (Assests).

Hierarchy – иерархия сцены. Здесь находятся все объекты текущей сцены. По умолчанию содержит камеру и светильник. Это окно можно так же назвать термином – граф сцены, т.к. любой объект сцены может иметь несколько потомков или быть потомком других объектов.

Scene – 3D вид разрабатываемой сцены. Аналогичные окна вы можете наблюдать в любом 3D редакторе. Позволяет манипулировать объектами сцены (положение, вращение, масштаб, редактировании ландшафта например и т.д.). При запуске проекта вместо окна Scene появляется окно Game, в котором отобразится вид из камеры (до запуска вид отображается в окне предварительного просмотра). Вверху над окнами 1 и 2 расположены кнопки: слева – кнопки управления видом окна Scene и манипуляций с объектами, посередине – кнопки запуска (остановки) отладки проекта.

Inspector – отображает и редактирует свойства объекта, выбранного в окнах  Hierarchy, Project и др. Так, для объекта сцены будут отображены настройки трансформаций, слоев и других компонентов, прикрепленных объекту.

Project – окно, управляющее ресурсами. Здесь будет находиться все, начиная от моделей, заканчивая материалами, шрифтами, скриптами и т.д. Работа с окном Project напоминает работу с папкой файловой системы. В этом окне можно  создать папочки для текстур, материалов и скриптов. В них можно добавить  соответствующие файлы. Что бы это сделать есть два основных способа: перетащить файлы изображений из проводника Windows в нужную папку окна Project либо щелкнуть правой кнопкой мыши по нужной папке в окне Project и выбрать пункт контекстного меню «Import New Asset…».

Рядом с кнопкой Project находится кнопка Console, которая активизирует окно Console – обычно используется при отладке ошибок.

Панель инструментов

Панель инструментов находится под основным меню и содержит 2 выделенных на рисунке блока элементов — Transform Tools (Инструменты трансформации) и Transform Gizmo Toggles (переключатели гизмо).

Как работать с этими инструментами рассмотрим на примере определения относительно объекта Plane положения параллелепипеда (создается из объекта Cube).

Здесь аналогия с задачей определения положение рупорной антенны в пространстве. Только вместо рупора используется параллелепипед.

Порядок выполнения задания.

При создании проекта в нем определены только 2 объекта – Main Camera и Directional Light. Добавим еще объект «плоскость» (GameObject ->3D Object ->Plane) и объект «куб» (GameObject ->3D Object-> Cube). Включите на панели инструментов Move Tool.

Можно перемещать объект, передвигая курсором оси координат. При этом изменение положения (Position) куба отразятся в свойствах компонента Transform.

Аналогично можно работать с инструментами Rotate Tool, Scale Tool и другими.

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

Мы совместили угловые точки объектов, а теперь необходимо совместить систему координат куба с угловой точкой. Перед этим необходимо еще перенести опорную точку (Pivot) системы координат на середину нижнего правого ребра куба.

По умолчанию система координат располагается в средней (Center) точке объекта. Для определения положения Pivot-точки необходимо в свойствах компонента Box Collider изменить координаты центра (Center).

Теперь можете совместить Pivot-точку с угловой точкой плоскости. Для этого необходимо переместить куб через  Move Tool на половину размера его стороны (- 0.5) вдоль оси Z.

Начало системы координат можно переключать из Pivot-точки в Center-точку через  Gizmo переключатели  Pivot / Center.

Осталось сделать из куба параллелепипед и повернуть его в соответствии с заданием относительно осей координат, выходящих из Pivot точки. Параллелепипед делаем через Scale Tool.

При помощи инструмента Rotate Tool поверните параллелепипед относительно системы координат, привязанной к Pivot точке. Сначала относительно оси Z.

В этом положении включите Move Tool и посмотрите, как расположены оси при Gizmo переключении  Pivot / Center и Local/Global. Например включение Center и  Global дает такое положение осей координат:

Сочетание переключателей  Pivot / Center и Local/Global позволяет задавать 4 системы координат с различными положениями начала координат и направления осей.

Используя инструмент Rotate Tool и различные положения Gizmo переключателей выполните еще 2 поворота вокруг осей  Y и Z, чтобы получить следующий результат:

Игровые объекты и их компоненты. Rigidbody

При создании проекта в нем определены только 2 объекта – Main Camera и Directional Light. Добавим еще объект «плоскость» (GameObject ->3D Object ->Plane) и объект «куб» (GameObject ->3D Object-> Cube). Воспользовавшись инструментами Rotate Tool и Move Tool создадим сцену, в которой куб нависает над плоскостью – примерно так, как это показано на рисунке

При изменении положения объектов изменяются свойства компонента Transform (в окне 4). Вид на сцену также определяется через свойство компонента Camera объекта Main Camera. Чтобы понять специфику создания вида обратитесь к рисункам  из раздела Построение вида.

Для установления взаимодействия между созданными геометрическими объектами необходимо добавить к ним соответствующие физические свойства. Физический движок среды используют систему динамики твердых тел (Rigid Body), для создания реалистичного движения. Это означает, что вместо статичных объектов, находящихся в виртуальном пространстве сцены, мы имеем объекты, у которых могут быть следующие свойства:  масса (Mass), гравитация (Use Gravity) и другие.

Выделите в окне 1 объект Cube и добавьте к нему компонент Rigidbody (Component -> Physics -> Rigidbody). В соответствующих полях переменных этого компонента mass и drag в окне 4 (Inspector) выставляются величины массы и скорости падения (притяжения к земле). Теперь при запуске проекта можно увидеть, как с высоты на созданную плоскость падает куб под действием силы тяжести. Причем, падение после соприкосновения с плоскостью прекращается, и куб остаётся на плоскости.

Добавим упругости кубу, чтобы он  после соприкосновения с плоскостью отскакивал. Для этого сначала добавим в проект физический материал (Assets->Create->Physic Material ). В окне 6 (Assets) появится пиктограмма нового материала, выделите ее. В окне Inspector отобразятся свойства материала, отредактируйте их.

Снова выберите куб. В окне Inspector вы можете увидеть компонент Box Collider, одним из параметров которого является Material (по умолчанию значение None(Physics Material)). Кликните на кружочке справа от него, и выскочит окно выбора физического материала. Выберите New Physic Material. Теперь, запустив проект, вы увидите, как после падения куб начнет отскакивать от плоскости. Если вы хотите, чтобы куб  проходил плоскость без остановки, вам необходимо выключить триггер (Is Trigger) компонента Box Collider.

C# скрипты

Под термином «скрипт» Unity3D подразумевает файл с исходным кодом, в котором описывается класс, унаследованный, от класса MonoBehaviour. Скрипты представляют собой пользовательские компоненты, которые добавляют «поведение» объекту сцены, так же как и стандартные компоненты.

Добавьте к сцене еще один куб (GameObject ->3D Object-> Cube). Растяните его по горизонтали в 5-ть раз и по вертикали в 2-а раза и расположите, как показано на рисунке.

В этом уроке важны названия объектов. Назовите плоскость Floor, а куб, представляющий стену — Wall. Создайте скрипт (Assets > Create > С# Script). Назовите скрипт Boxdrop.

Дважды кликните на скрипте, откроется Visual Studio редактор c подготовленным каркасом кода.

Если откроется другой редактор, то выполните настройки, чтобы файлы с расширением .cs открывались через Visual Studio

Код состоит из подключенных библиотек и основного класса с методами Start() и Update():

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
 // Start is called before the first frame update
 void Start()
 {
 
 }

// Update is called once per frame
 void Update()
 {
 
 }
}

Метод Start() выполняется сразу после загрузки сцены, метод Update() вызывается в каждом кадре. В первом примере мы не будем использовать эти методы.

Код замените следующим:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Boxdrop : MonoBehaviour
{
 // Метод, вызываемый при столкновении объекта
 void OnCollisionEnter()
 {
 Debug.Log("Hit Something"); // сообщение в консоль Unity 
 }
}

Обратите внимание, что название класса всегда должно совпадать с названием скрипта (регистр букв тоже имеет значение).

Функция OnCollisionEnter определяет столкновение объекта с другими объектами. А статический метод Log класса Debug пишет сообщение в консоль Unity.

В редакторе Unity добавьте скрипт как компонент для падающего куба. Для этого необходимо перетащить скрипт из окна 6 на куб.

Откройте окно консоли (кнопка Consol над окном 5) и запустите проект. В момент, когда куб касается пола или стенки, консоль будет выдавать соответствующее сообщение.

Немного изменим код. Теперь метод OnCollisionEnter будет определять объект, с которым происходит столкновение:

// параметр - объект класса, с которым происходит столкновение
void OnCollisionEnter(Collision myCollision) {
// определение столкновения с двумя разноименными объектами
if (myCollision.gameObject.name == "Floor") {
Debug.Log("Hit the floor");
}
else if (myCollision.gameObject.name == "Wall") {
Debug.Log("Hit the wall");
}
} 

Префабы

Префаб  – это объект, который можно копировать, причем все экземпляры при копировании будут иметь те же компоненты.

Итак, у нас на сцене присутствует куб, который падает и выдает сообщения в консоль при столкновении с объектами. Что, если мы хотим создать множество таких же кубов (с уже добавленными компонентами)? Нужно создать префаб.

Чтобы создать префаб из куба перетащим его из окна иерархии объектов в окно ресурсов. Переименуем его в «BouncyBox».

Если вы хотите создавать экземпляры префаба, то вам требуется перетащить его на сцену (в окно 2). При этом префаб появится и в окне 1.  Если вы выделите префаб, то увидите, что он имеет те же компоненты (см. окно инспектора 4), как и у объекта Cube.

Запустите проект и увидите, что добавленный куб ведет себя точно так же, как и оригинальный.

Изменения в префабе автоматически применяются ко всем его экземплярам, однако вы можете изменять и отдельные экземпляры. Чтобы было чётко видно, что свойство в экземпляре префаба изменено, оно показывается в инспекторе жирным шрифтом. Если к экземпляру префаба добавлен совершенно новый компонент, то все его свойства будут написаны жирным шрифтом.

Уничтожение объектов при запуске (runtime)

Что делать, если нам требуется уничтожить объект спустя какое-то время? Это можно сделать, при помощи функции Destroy, которую будем вызывать из метода Start():

// метод Start() выполняется после загрузки сцены
void Start() {
// уничтожить объект, к которому прикреплен данный скрипт
Destroy(gameObject,  3);
// уничтожаем объект Wall, спустя 5 сек после загрузки сцены
// GameObject – имя класса
Destroy(GameObject.Find("Wall"),  5);
}

При запуске проекта увидим, что добавленный куб (экземпляр префаба) уничтожается одновременно с оригиналом.

Создание объектов при запуске (runtime)

Добавьте пустой объект (GameObject->Create Empty). Создайте C#cкрипт и назовите его Creater:

public class Creater : MonoBehaviour {
    public GameObject thePrefab;
void Start () {
  GameObject instance = new GameObject();
  instance = Instantiate(thePrefab,
                        transform.position,
                        transform.rotation) as GameObject;
}
    // Update is called once per frame
    void Update () {  
    }
}

Перетащите скрипт в окно 1 к созданному пустому объекту (c именем GameObject).

Перетащите префаб BouncyBox  из окна 6 в окно 4 в место указания значения thePrefab.

Поскольку переменная thePrefab объявлена в скрипте с модификатором public, вы можете задавать ее начальное значение прямо в Inspector View.

Нажмите Play и увидите, что на сцене появился еще один прыгающий кубик-клон.

Добавление текстуры

Для выполнения этого задания достаточно перетащить рисунки из места, где они у вас хранятся, в окно Assets открытого проекта Unity3d, а затем из окна Assets перетащить их на объекты сцены:

      

Подключение аудио

Unity примет файлы любых звуковых форматов — WAV, MP3, AIFF, и OGG. Скачайте Sound_18050, распакуйте его и по аналогии с выполнением предыдущего задания (с текстурой) перетащите сначала в окно Assets, а затем на объект сцены (Cube). У объекта появился компонент Audio Source. Нажмите Play, теперь запуск проекта сопровождается звуком автомобильной аварии.

Для работы со звуком в Unity3d вам потребуются как минимум два компонента:

  • AudioListener (аудио приемник);
  • AudioSource (аудио ресурс).

Обычно AudioListener является компонентом у камеры. Выберем камеру и убедимся в этом, посмотрев в Inspector View.

Если же мы хотим, чтоб аудиоклип прозвучал в определенный момент, нужно написать скрипт. Оставим поле Audio Clip у  компонента Audio Source пустым (None).  Создадим  c#-скрипт, назвав его PlaySounds. В скрипт запишем следующий код:

// открытая переменная для аудиоклипа
 public AudioClip myClip;
 new AudioSource audio; // объявляем компонент аудио-источника
 void Start()
 {
 // инициализируем источник звуков
 audio = GetComponent<AudioSource>();
 // проигрываем наш аудиоклип
 audio.PlayOneShot(myClip);
 }

Добавим скрипт на  Cube, а значение переменной myClip у скрипта проинициализируем в Inspector View звуковым файлом. Теперь, запустив проект, вы снова услышите звук.

Проигрывать аудио можно и без использования Audio Source. Удалим компонент Audio Source c объекта Cube, а код в теле метода Start() заменим следующим:

AudioSource.PlayClipAtPoint(myClip, transform.position);

PlayClipAtPoint – статическая функция класса AudioSource, которая создает новый GameObject с соответствующим Audio Source (в нашем случае это myClip). После проигрывания аудио-клипа функция удаляет GameObject.

Контрольное задание. Модифицируйте программу из раздела  Игровые объекты и их компоненты. Добавление физических свойств,  добавив звуковой эффект в конце падения — при соприкосновении объекта Cube c плоскостью или стеной (объектами Floor и Wall).

Создание таймера при помощи скриптов

Создадим С#-скрипт и назовем его Timer:

public class Timer : MonoBehaviour {
    public float myTimer = 5.0f;
    void Update () {
//Time.delaTime – время (cek) для отрисовки кадра (read only)
 if(myTimer > 0){
    myTimer -= Time.deltaTime;
  }else if(myTimer <= 0){
    Debug.Log("GAME OVER");
  }
}

Добавим скрипт к объекту GameObject. Нажмем Play и проследим за поведением переменной myTimer. Когда ее значение будет достаточно близким к нулю, то оно перестанет изменяться. При этом в окне консоли вы увидите сообщение GAME OVER.

Движение объектов

Поскольку движение должно быть непрерывно во времени, то основной код должен располагаться в методе Update():

void Update () {
// задаем движение объекту вдоль оси Oz
transform.Translate(new Vector3(0.0f, 0.0f, 1.0f));
}

Скорость можно задать не фиксированным вектором, а через переменную:

public float v = 5.0f;
void Update () {
transform.Translate(new Vector3(0.0f, 0.0f, v) * Time.deltaTime);
}

Если у вас на сцене есть объект с компонентом Rigidbody, то нужно задавать ему движение с помощью приложения силы (передав, таким образом, все расчеты движения физическому движку игры). В противном случае вы можете начать конфликтовать с физикой объекта.

Создадим C#-скрипт и назовем его Force. В методе Start() вызовем метод AddForce() компонента rigidbody (cвязанного с нашим объектом) и передадим ему вектор приложенной силы Vector3(0.0f, 0.0f, power). В классе заведем переменную типа float с именем power и значением, по умолчанию равным 500.0f:

public float power = 500.0f;
 public Rigidbody rb;
 void Start()
 {
 rb = GetComponent<Rigidbody>();
 rb.AddForce(new Vector3(0.0f, 0.0f, power));
 }

Сохраним скрипт и добавим его к нашему объекту. Теперь, если нажать Play, вы увидите, как куб падает не вниз, а под углом, из-за воздействия силы, приложенной вдоль оси Z.

Взаимодействие пользователя с приложением

Создайте новый проект. Добавьте на сцене плоскость (Plane) и куб (Cube). Создайте c#-скрипт, назвав его Exis, со  следующим кодом для функции Update():

void Update () {
// Если нажата клавиша "Jump"(по умолчанию это пробел)
if (Input.GetButtonUp("Jump")) {
Debug.Log("We Have Hit the Space Bar"); //сообщ. в консоль
  }
}

Добавьте скрипт объекту Cube. Теперь, если во время запуска проекта нажать и отпустить клавишу Space, в консоли появится соответствующее сообщение.

Давайте выясним, что такое «Jump». Идем в Edit->Project Settings->Input.   В Inspector’e открылся Input Manager. Разверните пункт Axis. Если выбрать Jump, видно, что свойству Name соответствует строка Jump, а значение свойства Positive Button есть space.

Теперь разверните пункт Axis -> Horizontal. Посмотрим на некоторые дефолтные параметры:

Параметр

Значение Комментарий

Negative Button

left

Клавиша для перемещения в отрицательном направлении

Positive Button

right

Клавиша для перемещения в положительном направлении

Alt Negative Button a

Альтернативная клавиша для перемещения в отрицательном направлении

Alt Possitive Button

d

Альтернативная клавиша для перемещения в положительном направлении

Type

Key or Mouse Button

Тип ввода, для перемещения вдоль данной оси (в нашем случае X)

Axis X axis

Ось объекта, вдоль которой мы будем перемещаться

Для того, чтобы использовать данное перемещение (Horizontal), нам потребуется в c#-скрипте метод GetAxis() класса Input:

private float horiz;
  void Update () {
    horiz = Input.GetAxis("Horizontal");
    Debug.Log(horiz);
  }

Теперь при запуске проекта, если зажать стрелку влево/вправо (или же a/d), в status bar’е вы увидите, как меняется значение переменной horiz.

Добавим еще строчку кода в Update(), сразу за Debug.Log():

transform.Translate(new Vector3(horiz, 0.0f, 0.0f));

Запустим сцену и нажмем на стрелку — вы увидите, как объект Cube начнет перемещаться вдоль оси X.

Соединения

Ниже рассмотрено, как использовать Fixed joint (неподвижное соединение) и Hinge joint (шарнирное соединение) для создания цепи у шара для разрушения зданий.

В новом проекте создадим объекты Plane  и Sphere. Изменим положение Sphere (0, 2.5, -1.2) и добавим к ней компонент Rigidbody. Добавим на сцену Cylinder. Изменим его масштаб (0.15, 0.25, 0.15), положение (0, 3.25, -1.2) и добавим компонент Rigidbody.

При запуске проекта сфера вместе с цилиндром опустятся на плоскость. При этом цилиндр отскочит от сферы.

Чтобы связать сферу и цилиндр – выберите сферу  и добавьте к ней компонент Fixed Joint (Component -> Physics -> Fixed Joint). Переменную Connected Body инициализируем значением Cylinder. Для этого достаточно перетащить Cylinder из окна Hierarchy в окно Inspector, на поле напротив Connected Body. При запуске проекта цилиндр уже не отскочит от сферы.

Теперь начнем создавать подвижные участки цепи.

Создадим объект Capsule (назовем его Chain1).  Масштаб и положение у него как у цилиндра. Еще добавьте компонент rigidbody. Переместите Chain1 чуть выше цилиндра, чтоб крайние грани объектов пересекались.

К объекту Cylinder добавим компонент Hinge Joint (Component -> Physics -> Hinge Joint), у которого переменную Connected Body инициализируем Chain1.

Нам потребуется еще один участок цепи. Выберем Chain1 и сделаем его дубликат (ctrl+D). Переименуем его в Chain2 и сдвинем его к верхушке Chain1. К Сhain1 добавим Hinge Joint, с Connected Body равным Chain2. Аналогично добавим Chain3.

В конце, мы добавим HingeJoint к Chain3, при этом мы не будем задавать значение Connected Body. В этом случае объект будет прикреплён «сам к себе» (точнее сказать к пустому месту в сцене).

Выделим (при нажатой клавише Shift) Sphere, Cylinder, Chain1, Chain2, Chain3 и наклоним их. Жмем Play и смотрим, как перемещаются наш шар с цепью.

Интерфейс пользователя (UI). Переключение сцен

Создайте проект, добавьте в него объекты Plane (назовем floor)  и Cube. Поместите объект Cube над плоскостью и добавьте к нему компонент Rigidbody. Замените имя сцены в папке Assets>Scenes на имя level.

Создайте новую сцену (Assets>Create> Scene). Сохраните сцену под именем gameover.

Добавьте в сцену текст (Game Object->UI->Text). Поменяйте значение свойства Text добавленного компонента на “Game Over!”. Так же можно поменять другие параметры, такие как размер (font size), выравнивание (alignment).

Создадим скрипт (назовем LoadLevel) со следующим кодом:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LoadLevel : MonoBehaviour
{
 void OnCollisionEnter(Collision myCollision)
 {
 if (myCollision.gameObject.name == "floor")
 {
 SceneManager.LoadScene("gameover");
 }
 }
}

Добавим скрипт объекту Cube.

Необходимо указать в настройках сборки (Build Settings) все сцены, которые хотим загружать в итоговом приложении. Перейдем в настройки сборки File->Build Settings и перетащим сцены level и gameover из Project View в верхнее поле Buil Settings.

При запуске проекта в момент, когда Cube опустится на плоскость, произойдет переключение со сцены level на сцену gameover.

Наследование на примере создания часов

В этом уроке мы напишем небольшой C# скрипт, который обеспечит перемещение стрелок очень простых часов.

Прежде всего, нам необходимо представить иерархию объектов. Добавьте в проект пустой GameObject (GameObject -> Create Empty), установите его в начале координат (0, 0, 0), и назовите Clock. Создайте еще три пустых объекта, назовите их Hours, Minutes и Seconds. Убедитесь, что они расположены в точке (0, 0, 0). Сделайте их child objects для объекта Clock ( Parent-Child отношения между двумя GameObjects устанавливаются путем перетаскивания одного объекта на другой в окне Hierarchy).

Наследование – это одно из наиболее важных понятий в Unity. Если GameObject является Parent другого GameObject, тогда Child GameObject будет двигаться, вращаться и масштабироваться также, как и Parent GameObject. Это подобно тому, как кисть руки будет двигаться вместе с рукой, а пальцы руки будут двигаться вместе с кистью.

Каждую из стрелок часов будем моделировать параллелепипедом. Создайте child cube для каждой стрелки (GameObject -> Create Other -> Cube). Измените их положение и масштаб:

  • для часовой стрелки – (0, 1, 0) и (0.5, 2, 0.5);
  • для минутной стрелки – (0, 1.5, 0) и (0.25, 3, 0.25);
  • для секундной стрелки – (0, 2, 0) и (0.1, 4, 0.1).

 

Создайте C# script, назовите его ClockAnimator и добавьте скрипт объекту Clock путем перетаскивания его из окна Project в окно Hierarchy.

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

private const float
 hoursToDegrees = 360f / 12f,
 minutesToDegrees = 360f / 60f,
 secondsToDegrees = 360f / 60f;

public Transform hours, minutes, seconds;

void Update () {
 DateTime time = DateTime.Now;
hours.localRotation = 
Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = 
Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = 
Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
 }
}

Чтобы задать движение стрелкам, прежде всего, необходимо получить доступ к их компонентам Transform. В скрипте это обеспечивается через открытые переменные класса Transform – hours, minutes, seconds. Эти переменные станут свойствами компонентов, которые вы определите в редакторе. Выберите объект Clock, затем перетащите объекты Hours, Minutes и Seconds из окна Hierarchy к соответствующим им свойствам в окне Inspector.

Запустим проект.

Объект Hours поворачивается на 360/12 градусов в час. Объект Minutes поворачивается на 360/60 градусов за минуту. Объект Seconds поворачивается на 360/60 градусов за секунду.

Чтобы задать движение стрелок часов используется метод update (), который вызывается при каждом обновлении кадра. Каждый раз необходимо знать текущее время, которое содержится в поле Now структуры DateTime.

Поскольку, мы наблюдаем в направлении оси Z, а Unity использует левостороннюю систему координат, то угол вращения по часовой стрелке должен быть отрицательный.
Часы работают в дискретном режиме. Для работы часов в аналоговом режиме скрипт запишется в виде:

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

private const float
 hoursToDegrees = 360f / 12f,
 minutesToDegrees = 360f / 60f,
 secondsToDegrees = 360f / 60f;

public Transform hours, minutes, seconds;
 public bool analog;
 void Update () {
 if (analog) {
 TimeSpan timespan = DateTime.Now.TimeOfDay;
 hours.localRotation =
Quaternion.Euler(0f,0f,(float)timespan.TotalHours * -
hoursToDegrees);
 minutes.localRotation =
Quaternion.Euler(0f,0f,(float)timespan.TotalMinutes * -
minutesToDegrees);
 seconds.localRotation =
Quaternion.Euler(0f,0f,(float)timespan.TotalSeconds * -
secondsToDegrees);
 }
 else {
 DateTime time = DateTime.Now;
hours.localRotation = 
Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
minutes.localRotation = 
Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
seconds.localRotation = 
Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
 }
 }
}

Для определения вращения объектов в скрипте используется статический метод Quaternion.Euler. Теоретические основы преобразований вращения  см. в статье Углы Эйлера и кватернионы.

В скрипт была добавлена отрытая boolean переменная analog. При этом она появилась в редакторе как свойство компонента ClockAnimator с флажком для управления ее значением. При установке флажка (галочки) часы работают в аналоговом режиме.

Создание окружающей среды

Создадим ландшафт. В главном меню выбираем GameObject ->3D Object->Terrain. Модель ландшафта пока совершенно плоская и не очень похожа на ландшафт. Кнопки редактирования ландшафта (в  окне Inspector) позволяют изменить это.

Крайняя левая кнопка (с изображением кисти) позволяет создать рельеф ландшафта и раскрасить  его (применить текстуры). Вторая кнопка (с деревьями) включает мощный инструмент массовой посадки деревьев. Третья кнопка (с цветами) позволяет делать все то же самое что и с деревьями только относится к траве. Последняя кнопка (с изображением шестеренки) позволяет настроить различные параметры ландшафта.

Выбираем кнопку с шестеренкой и меняем размеры ландшафта:

  • Terrain Width — 200
  • Terrain  Length — 200
  • Terrain Height — 50

Выбираем кнопку с кистью и выполняем ее настройки:

Height — определяет максимальную высоту рельефа; Brush Size — размер кисти; Opacity — интенсивность взаимодействия, скорость создания рельефа.

Двигая выбранной кистью по поверхности создаем рельеф из возвышенностей. Меняем кисти, чтобы сделать более разнообразной текстуру поверхности — более каменистой.

Если необходимо создать плоскую поверхность на определенной высоте, то устанавливаете свойство Height на эту высоту и после этого обрабатываете участок поверхности кистью. Стирание возвышенностей выполняется, когда Height=0.

Для сглаживания острых углов в настройках под кистью вместо Set Height выбираете Smooth Height.

Вместо кисти выберем кнопку с цветами (3-я, начиная слева). Выполним настройки текстуры (кнопки Edit Details->Add Grass Texture->Dуtail Texture). Появляется окно с доступными в проекте образцами текстуры.

Их нам недостаточно. Добавим в проект ресурсы из  Standard assets. Для этого нажмем кнопки меню Assets->Import Package->Custom Package, указываем, где находятся ресурсы  и выделим в окне необходимые ресурсы Environment

Если Вы еще не подгрузили на свой компьютер ресурсы Standard assets, то сделайте это.

Снова нажимаем кнопки Edit Details->Add Grass Texture->Dуtail Texture и выбираем подходящую текстуру

Водим кистью по рельефу. Аналогичные действия выполняем для кнопки с деревьями(2-я, начиная слева) . Результат представлен на рисунке:

Следует отметить, что при работе с текстурой система часто зависает и глючит.

Более детальное изложение темы создания окружающей среды можно посмотреть в видео-уроках:

Полезные ссылки:

 

 

Автор: Николай Свирневский