Unity3d. Уроки от Unity 3D Student (B21-B24)

Всем привет.Ссылки на предыдущие уроки:

Базовый урок 21 — Вычисление расстояния между объектами В уроке будет показано, как получить расстояние между двумя точками в трехмерной сцене, используя метод Vector3.Distance. Кроме того, в дополнение к оригинальному уроку я расскажу о свойстве Vector3.sqrMagnitude, при помощи которого можно получить более оптимизированный код вычисления расстояния.При разработке игры часто возникает необходимость узнать расстояние между объектами. Один из самых простых способов это сделать — использовать метод Distance класса Vector3.Рассмотрим следующую сцену: кубик fallbox, падающий вниз на более большой куб Cube; точечный источник света Point light, находящийся между ними; и, конечно, камера.

2dd0b44ad6317b2e2383405739ebf9c6.png

Если мы захотим, чтобы источник света загорался только тогда, когда он находится в пределах определенной дистанции от падающего куба, то нужно создать следующий скрипт: Код на JavaScript:

var box: Transform; function Update () { var dist: float = Vector3.Distance (box.position, transform.position); Debug.Log (dist); if (dist <= 10){ light.enabled = true; }else{ light.enabled = false; } } Код на C#: public Transform box;

private void Update () { float dist = Vector3.Distance (box.position, transform.position); Debug.Log (dist);

if (dist <= 10) //вместо if/else можно использовать более сокращенную запись: light.enabled = dist <= 10; { light.enabled = true; } else { light.enabled = false; } } В скрипте мы сперва объявляем переменную box, в которой будем хранить ссылку на компонент Transform нашего падающего ящика. Затем в Update вызываем метод Vector3.Distance, передав в качестве аргументов координаты объектов, между которыми требуется вычислить расстояние. Полученное расстояние заносим в переменную dist и сравниваем его с необходимым значением (10 в нашем примере). Если расстояние не превышает заданное значение — включаем компонент света, в противном случае — выключаем. При помощи метода Debug.Log выводим значение текущего расстояния в консоль.Добавляем скрипт на объект света Point Light, в поле скрипта Box перетаскиваем fallbox, запускаем сцену. Кубик падает вниз, свет не горит. При расстоянии между светом и кубиком fe8ce46c523d4bd4a0eea9b42dfdb434.png

Примечание от переводчика №1: расстояние также можно подсчитать, вычислив разность между координатами объектов, получив в результате объект типа Vector3, а затем обратиться к его свойству magnitude: Код на C#:

float dist = (box.position — transform.position).magnitude; Примечание от переводчика №2: использование метода Vector3.Distance или свойства Vector3.magnitude имеет один недостаток. Дело в том, что при расчете расстояния сначала получается квадрат значения расстояния, из которого, соответственно, надо извлечь корень. Извлечение корня является достаточно затратной операцией и при частом вызове для большого числа объектов может привести к падению производительности. В данном случае в качестве оптимизации можно использовать свойство Vector3.sqrMagnitude. Оно вернет квадрат расстояния, что вычисляется быстрее простого расстояния благодаря отсутствию операции извлечения корня. Полученный квадрат расстояния нужно будет сравнить с квадратом заданного значения, т. е. для примера из урока это будет выглядеть так: Код на C#, укороченный, оптимизированный, с константой вместо «магического» числа: public Transform box; private const int cMaxDistance = 10;

private void Update () { float dist = (box.position — transform.position).sqrMagnitude; light.enabled = dist <= cMaxDistance * cMaxDistance; //квадрат расстояния сравниваем с квадратом заданного предела! Debug.Log(dist); } Ссылка на оригинальный урокДополнительные материалы: Ссылка на документацию метода Vector3.DistanceСсылка на документацию свойства Vector3.sqrMagnitudeБазовый урок 22 — Создание паузы при помощи метода WaitForSeconds В уроке рассказывается, как сделать паузу (задержку) в игре с использованием метода WaitForSeconds и инструкции yield.Если вы хотите реализовать паузу между некими игровыми событиями (например, создание игровых объектов через определенные промежутки времени), то необходимо воспользоваться Корутинами (сопрограммами). Корутина — это специальным образом оформленный метод, работающий в основном потоке игры, и обычно вызываемый после метода Update. Корутина, в зависимости от заданных условий, может прервать свое выполнение в определенной точке своего кода, а затем вновь продолжить работу (подробнее о корутинах есть на хабре — прим. переводчика).Посмотрим на сцену ниже. На ней есть куб, играющий роль земли, источник света, камера и пустой объект под именем spawn point, висящий над землей. Кроме того, в папке Project есть префаб weight — кубик с компонентом rigidbody. Наша цель — периодически создавать кубики из префаба в точке spawn point, после чего они будут падать на землю.

6990873604e64e5ba72e3b48baad5b18.png

Создать объект легко — нужно воспользоваться уже знакомым методом Instantiate. Однако, если мы просто напишем вот такой скрипт и добавим его к объекту spawn point…Код на JavaScript:

var box: GameObject; //здесь храним ссылку на префаб порождаемого объекта function Update () { Instantiate (box, transform.position, transform.rotation); //создаем объект } … то получим примерно следующую картину: cacd9d51853840c982c2fb397a746adc.png

Буквально за пару секунд выполнения у нас создалось слишком много объектов. Это не удивительно, ведь мы поместили создание объекта в метод Update, который вызывается каждый кадр игры, т. е. несколько десятков раз в секунду. Любые попытки как-то вставить задержку в метод Update, чтобы объекты создавались реже, ни к чему хорошему не приведут — это уменьшит FPS игры. Вместо этого нам поможет корутина.Давайте реализуем скрипт создания объектов следующим образом: Код на JavaScript:

var box: GameObject; var readynow: boolean = true; function Update () { if (readynow){ MakeBox (); //в JS просто запускаем корутину } } function MakeBox (){ readynow=false; Instantiate (box, transform.position, transform.rotation); yield WaitForSeconds (2); //приостанавливаем выполнение корутины на 2 секунды readynow=true; } Код на C#: public GameObject box; private bool readynow = true; private void Update () { if (readynow) StartCoroutine (MakeBox ()); //в C# для запуска корутины нужно использовать метод StartCoroutine } private IEnumerator MakeBox () //Корутина должна возвращать IEnumerator { readynow = false; Instantiate (box, transform.position, transform.rotation); yield return new WaitForSeconds (2); //код приостановки корутины немного сложнее, чем в JS readynow = true; } Итак, в переменный box мы храним ссылку на префаб порождаемого объекта. Булева переменная readynow служит для определения, запускать ли сейчас метод-корутину MakeBox, которая создает объект. Внутри корутины MakeBox мы сперва запрещаем ее вызов (readynow = false), потом создаем объект методом Instantiate, а затем используем связку yield / WaitForSeconds (обратите внимание на различия в коде для JS и в коде для C# — прим. переводчика). Эта связка позволяет приостановить выполнение корутины, в данном случае, на 2 секунды, а потом вернуться обратно и продолжить выполнение, где мы теперь разрешаем вызов корутины (readynow = true). Метод Update при этом не простаивает эти 2 секунды, а продолжает выполняться, только не запускает заново новую корутину, пока не отработает предыдущая.Напоминаю, что скрипт надо добавить к объекту spawn point, перетащить в поле скрипта Box префаб кубика и запустить сцену. Теперь кубики создаются через каждые 2 секунды.602dafc19130460bb4e0afdb9f35c1a1.png

Ссылка на оригинальный урок

Дополнительные материалы: Ссылка на документацию класса WaitForSecondsБазовый урок 23 — Система частиц В уроке будет показано, как создать простой взрыв, используя систему частиц.Примечание от переводчика: в оригинальном уроке используется версия Unity, в которой работа с системами частиц сильно отличается от текущей версии Unity. В следствии этого перевод будет сильно отличаться от оригинала, поскольку я опишу работу в текущей версии Unity (4.3.Х).Если вы хотите создать дым, огонь, пыль или иное распространение неких частиц, то можно использовать систему частиц. В этот раз на нашей сцене есть падающий кубик, который исчезает при соприкосновении с землей. Наша цель — сделать так, чтобы исчезновение сопровождалось эффектом взрыва.

63d9efc3834a4c21b79c8e700cc068e4.png

Давайте создадим новую систему частиц: меню GameObject → Create Other → Particle System. Добавится новый объект с компонентами Transform и Particle System. В Particle System перечислено множество настроек, изменяя которые можно добиться различных эффектов. Для эффекта взрыва зададим следующие настройки: В шапке компонента: Duration = 0.10 — продолжительность генерирования частиц. Поскольку взрыв будет кратковременным, мы можем задать самое маленькое значениеLooping — снимем галочку — флаг зацикливания генерации частиц. Для одиночного взрыва его нужно снятьStart Lifetime = 0.4 — продолжительность жизни частиц. Частицы будут существовать указанное время, после чего исчезнутStart Speed = 25 — начальная скорость движения частицStart Size = от 1 до 3 — начальный размер частиц. Здесь мы внесем разнообразие и зададим не константное значение, а случайное значение между двумя константными. Для это нужно нажать маленький треугольник справа от значения параметра и выбрать в меню пункт «Random between two constants», после чего ввести значения 1 и 3.c8982a6b5ecf47b388ff473eba3604dd.pngНа вкладке «Emission»: Rate = 0 — число генерируемых частиц, как ни странно, установим в 0. Пояснение в следующем параметреBursts — позволяет задать массовый выброс частиц, что хорошо подходит для взрыва. Для этого надо нажать на кнопку с плюсиком и в появившейся строки задать значения Time = 0, Particles = 20. Благодаря этому, сразу после появления объекта системы частиц на сцене будет произведен одновременный выброс 20 частиц.На вкладке «Shape»: Shape = Sphere — задает фигуру, определяющую направление распространения частиц. Так как мы хотим распространить частицы взрыва во все стороны — используем сферу.На вкладке «Renderer»: Material — необходимо задать материал для отображения частиц. Пока установлен материал по умолчанию, частицы отображаются серыми шариками. Чтобы сделать что-то более интересное, необходимо создать свой материал: e06df3b75bcc4447b539b97d809b3759.pngВ окне Inspector появиться новый материал. Зададим ему любое имя, затем установим в поле Shader значение Particles/Alpha Blended и добавим текстуру для взрыва (рисунок звездочки): d8c34baff7d5416aaa8531b510456171.pngТеперь этот материал надо добавить в поле Material вкладки Renderer нашей системы частиц (перетащив материал мышью или выбрав его из меню).На всякий случай, продублирую настройки скриншотом (неиспользованные вкладки вырезаны): 35ced4dba506487386e03f87518c126a.png

Потестируем наш взрыв. Кликнем по созданной системе частиц в окне Hierarchy. Если все сделано правильно, в разные стороны рассыпался ворох звезд.

c3161a7788cc4465ace6592203f8e9f9.png

Теперь необходимо написать небольшой скрипт и добавить его к нашему взрыву. Это скрипт будет отвечать за уничтожение системы частиц со сцены, после того, как все ее частицы прекратят существование: Код на JavaScript:

private var ps: ParticleSystem; function Start () { ps = GetComponent (ParticleSystem); } function Update () { if (ps) { if (! ps.IsAlive ()) { Destroy (gameObject); } } } Код на C#: private ParticleSystem ps; private void Start () { ps = (ParticleSystem)GetComponent (typeof (ParticleSystem)); } private void Update () { if (ps) if (! ps.IsAlive ()) Destroy (gameObject); } В скрипте мы сохраняем компонент системы частиц в переменной ps. В методе Update проверяем присутствие компонента на сцене. Если он есть — проверяем, «жив» ли он. Это делается при помощи вызова метода IsAlive — он вернет false, если система частиц больше не генерирует частицы и все ранее сгенерированные частицы исчезли. Если это так — удаляем объект системы частиц.Все готово, чтобы из взрыва сделать префаб. Нажимаем в окне Project кнопку Create — Prefab, называем префаб starBursts, перетаскиваем на него взрыв из окна Hierarchy и удаляем взрыв со сцены.Теперь нам только осталось написать скрипт и добавить его к падающему кубику: Код на JavaScript:

var stars: ParticleSystem; function OnCollisionEnter (col: Collision) { Instantiate (stars, transform.position, transform.rotation); Destroy (gameObject); } Код на C#: public ParticleSystem stars;

private void OnCollisionEnter (Collision col) { Instantiate (stars, transform.position, transform.rotation); Destroy (gameObject); } При соприкосновении коллайдера кубика с любым другим коллайдером, мы создаем методом Instantiate взрыв и удаляем кубик методом Destroy. В поле stars скрипта необходимо поместить префаб системы частиц нашего взрыва.Запускаем, любуемся эффектным уничтожением кубика.

Ссылка на оригинальный урок (с использованием старой системы частиц)

Дополнительные материалы: Документация компонента Particle SystemБазовый урок 24 — Работа с циклом «For» В уроке рассказывается об использовании оператора цикла «For», с помощью которого можно повторять необходимые действия, пока выполняется заданное условие.При создании игры часто возникает задача выполнить несколько раз подряд некие повторяющиеся действия. Для этого не стоит «копипастить» код, а нужно воспользоваться циклами.На нашей сцене есть земля, свет, камера и пустой объект creator.

65055381b66b44ebbe8c96113a5c3487.png

Мы хотим, чтобы из объекта creator с небольшими паузами создались из префаба несколько других объектов. Для этого напишем следующий скрипт: Код на JavaScript:

var myPrefab: Rigidbody; var distanceMultiplier: float = 2; function Start (){ var i: int = 0; var pos: Vector3 = transform.position; for (i=0; i<=3; i++){ Instantiate(myPrefab, Vector3(pos.x+i*distanceMultiplier, pos.y, pos.z), transform.rotation); yield WaitForSeconds(0.5); Debug.Log("made ball "+i); } } Код на C#: public Rigidbody myPrefab; private const float distanceMultiplier = 2f;

private IEnumerator Start () { Vector3 pos = transform.position; for (int i=0; i<=3; i++) { Instantiate(myPrefab, new Vector3(pos.x + i * distanceMultiplier, pos.y, pos.z), transform.rotation); yield return new WaitForSeconds(0.5f); Debug.Log("made ball "+i); } } Мы завели переменную для хранения создаваемого объекта myPrefab. В уроке это шарик с компонентом Rigidbody, но это не принципиально. Переменная distanceMultiplier нужна, чтобы разнести в пространстве создаваемые объекты. В методе Start мы сохраняем позицию объекта creator, которая будет служить основой для размещения создаваемых объектов. Затем происходит запуск цикла for.В первой строке цикла задано условие работы. Цикл будет выполняться, пока истинно условие. Условие состоит из трех частей:

i=0 — задаем переменной-индексу начальное значение i<=3 — устанавливаем, собственно, условие — выполнять цикл, пока значение индекса не больше 3 i++ — увеличиваем значение индекса на 1 При данной записи цикл отработает 4 раза: пока переменная i равна 0, 1, 2 и 3. Когда i станет равной 4 — произойдет выход из цикла.Внутри цикла мы выполняем уже знакомые действия. Сперва создаем объект, задав ему позицию, равную позиции объекта creator, за исключением координаты х — к ней мы прибавляем текущее значение индекса, умноженное на константу distanceMultiplier. Затем делаем паузу на полсекунды, чтобы объекты не создавались одновременно. В конце цикла пишем отладочное сообщение в лог.Добавляем скрипт к объекту creator, в поле скрипта myPrefab переносим префаб сферы с компонентом Rigidbody, запускаем сцену. Четыре сферы, одна за другой, появились из ниоткуда и попадали на землю.b7444f1aa551488dad75a4c778cee8f6.png

Ссылка на оригинальный урок

Дополнительные материалы: Ссылка на MSDN о различных циклах

© Habrahabr.ru