Сайт о телевидении

Сайт о телевидении

» » Unity скрипт движения камеры за персонажем

Unity скрипт движения камеры за персонажем

Привет, Хабр!

Я, как и обещал, продолжаю делиться с вами знаниями, приобретенными в процессе освоения 2D-режима Unity. От начинающего, так сказать, начинающим . Систематизирую, улучшаю и прогрессирую вместе с вами. Сегодня мы добавим к содержимому первой статьи управление камерой, сбор бонусов и первый способ умереть в игре. Если вам, как и мне, не терпится приступить, то добро пожаловать под кат.

И да, гифок там еще больше, чем в

Скорее в бой!

Чтобы камера во время игры не стояла статично, а плавно двигалась за персонажем, используем заранее подготовленный скрипт. Все по-прежнему просто: берем его и перетаскиваем, но уже на камеру.

Сам скрипт очень короткий и выглядит вот так:

Using UnityEngine; using System.Collections; public class newcam: MonoBehaviour { public float dampTime = 0.15f; private Vector3 velocity = Vector3.zero; public Transform target; // Update is called once per frame void Update () { if (target) { Vector3 point = camera.WorldToViewportPoint(new Vector3(target.position.x, target.position.y+0.75f,target.position.z)); Vector3 delta = new Vector3(target.position.x, target.position.y+0.75f,target.position.z) - camera.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, point.z)); //(new Vector3(0.5, 0.5, point.z)); Vector3 destination = transform.position + delta; transform.position = Vector3.SmoothDamp(transform.position, destination, ref velocity, dampTime); } } }

Main camera, на которую повешен этот скрипт, следует за объектом, который указан у него (скрипта) в публичной переменной target. К слову - все публичные переменные в скриптах можно изменять прямо из редактора Unity. В нашем случае укажем на храброго носатого героя, запустим игру и проверим.

Теперь можно сделать префаб из платформы (помните как? если нет, смотрите первую статью) и раскидать их по сцене произвольным образом. В моем случае, выглядеть это все будет примерно так:

Прогуляемся по уровню. Прыжок, еще прыжок… Неудачное движение и герой падает в яму и не собирается возвращаться назад. Как нам с этим бороться? Да легко! Основная идея в том, что в пустоте под платформами будут расположены невидимые объекты, при пересечении которых можно будет загрузить уровень заново или вернуть персонажа назад с, допустим, минус одной жизнь. Для этого нам понадобятся пустой объект, которому добавим Box Collider (вытянутый по горизонтали) и поставим на нем в инспекторе галку Is trigger. Триггер в Unity отличается от простого коллайдера тем, что он не является препятствием, но при пересечении с объектом может вызвать какое-то событие. Объект переименуем в dieCollider и напишем немного кода для обработки падения. Вот вам гифка по случаю такого длинного абзаца:

Как можно быстрее найдем во вкладке Assets и, после двойного клика, впервые познакомимся с MonoDevelop в рамках этой серии уроков.

Для обработки пересечения с триггером используется функция OnTriggerEnter2D. Для простого коллайдера аналогично OnCollisionEnter2D.
Добавим следующий код:

Void OnTriggerEnter2D(Collider2D col){ if (col.gameObject.name == "dieCollider") Application.LoadLevel (Application.loadedLevel); }

Как видите, все логично. Если имя объекта, с которым мы столкнулись, совпадает со строкой «dieCollider», то перезагружаем уровень вполне очевидным методом - загружаем еще раз уровень, который уже загружен.
Теперь можно упасть в яму и…

Отлично, персонаж возвращается на стартовую позицию. Сделаем префаб из dieCollider"а, расставим его копии во всех опасных местах и осмотримся: чего-то явно не хватает. Конечно, бонусов, которые можно собирать! Принцип их создания абсолютно аналогичен созданию областей, которые возвращают нас назад. Мы будем снова использовать триггеры, только теперь будем сталкиваться не с невидимым объектом, а со вполне конкретной звездой. Работает это так:

Теперь вернемся в MonoDevelop и напишем немного кода. Объявим float переменную score (которую на первое время можно сделать публичной, чтобы следить за результатом в процессе создания игры) и добавим следующий код в функцию OnTriggerEnter2D

If (col.gameObject.name == "star") { score++; Destroy (col.gameObject); }

Он выполняет две простые функции - увеличивает результат на единицу и уничтожает объект, с которым мы столкнулись (в данном случае звезду). Так как из бонуса мы уже сделали префаб, раскидаем немного по уровню и посмотрим что будет, если их собирать. Обратите внимание на переменную score в правом нижнем углу экрана.

Теперь давайте научимся отображать результат на экране, ведь никто не хочет играть в игру прямо в редакторе и смотреть где-то сбоку количество собранных звезд. В этом нам поможет функция OnGUI(), которая прекрасно умеет отрисовывать на экране текстовые блоки, кнопки и прочие полезные вещи.

Void OnGUI(){ GUI.Box (new Rect (0, 0, 100, 100), "Stars: " + score); }

Проще некуда. Прямо на ДжиЮАе рисуется квадрат с координатой левого верхнего угла (0,0) и размерами 100x100. В нем выводится текст, прямо говорящий нам о количестве собранных звездочек.

Вот так. По итогам двух уроков мы научились создавать игровое окружение, добавили в игру бонусы, возможность умереть и начать заново. В следующий раз я покажу вам как сделать несколько уровней и заставить нашего персонажа бросаться чем-нибудь во что-нибудь. Но этого определенно мало. Поэтому добавим немного интерактивности в наше с вами обучение: голосуйте в прикрепленном опросе и я обязательно добавлю что-то на выбранную вами тему.

И да: напомню, что прямо сейчас проходит

Камеры являются устройствами, которые захватывают и отображают мир игроку. Путем настройки и манипулирования камерами, вы можете сделать презентацию своей игры поистине уникальной. Вы можете иметь неограниченное количество камер в сцене. Вы можете настроить рендеринг камерами в любом порядке, на любом месте экрана, либо только в определенных частях экрана.

Свойства

Свойство: Функция:
Clear Flags Определяет, какие части экрана будут очищены. Это удобно при использовании нескольких камер для отрисовки разных элементов игры.
Background Цвет, применяемый для фона после отрисовки всех элементов, в случае отсутствия скайбокса.
Culling Mask Включение или исключение слоёв объектов на рендер этой камерой. Назначение слоёв объектам производится через Inspector.
Projection Переключает способность камеры симулировать перспективу.
Perspective Камера будет рисовать объекты в перспективе.
Orthographic Камера будет рисовать объекты равномерно, без эффекта перспективы.
Size (когда выбран ортографический режим) Размер зоны видимости камеры для ортографического режима.
Field of view (когда выбран режим перспективы) Ширина угла обзора камеры, измеряется в градусах по локальной оси Y.
Clipping Planes Дистанция, на которой камера начинает и заканчивает рендеринг.
Near Ближайшая точка относительно камеры, которая будет рисоваться.
Far Дальняя точка относительно камеры, которая будет рисоваться.
Normalized View Port Rect Четыре значения, отражающие то, в какой области экрана будет выведено изображение с камеры, в экранных координатах (от 0 до 1).
X Начальная позиция области по горизонтали вида камеры, который будет рисоваться.
Y Начальная позиция области по вертикали, где вид камеры будет рисоваться.
W (Ширина) Ширина вида камеры на экране.
H (Высота) Высота вида камеры на экране.
Depth Позиция камеры в очереди отрисовки. Камеры с большим значением будут нарисованы поверх камер с меньшим значением.
Rendering Path Опции для определения методов рендеринга для камеры.
Use Player Settings Камера использует метод рендеринга, установленный в Player Settings.
Vertex Lit Все объекты рисующиеся этой камерой будут рендериться как Vertex-Lit-объекты.
Forward Все объекты будут рендериться с одним проходом на материал.
Deferred Lighting Все объекты будут рендериться сначала без освещения, а затем будет произведён рендер освещения для всех объектов разом, в конце очереди рендеринга.
Target Texture Ссылка на Render Texture , которая будет содержать результат рендеринга камеры. Назначение этой ссылки отключает способность камеры рендерить на экран.
HDR Включение технологии High Dynamic Range.

Детали

Камеры очень важны для демонстрации вашей игры игроку. Они могут быть изменены, заскриптованы, наследованы для получения различных визуальных эффектов. Для паззла вы можете сделать камеру статичной и охватывающей обзором весь паззл. Для шутера от первоого лица вы можете сделать камеру дочерней по отношению к игроку и разместить её на уровне глаз персонажа. Для гоночный игры вы можете закрепить камеру позади автомобиля и заставить её следовать за ним.

Вы можете создать несколько камер и назначить каждой свою глубину(Depth). Камеры будут отрисовываться от низшей глубины до высшей глубины. Другими словами, камера с Depth 2 будет отрисована поверх камеры с Depth 1. Вы можете настроить значение свойства Normalized View Port Rectangle для изменения позиции и размера изображения с камеры на экране, например для создания нескольких экранов в одном, или для создания зеркала заднего вида.

Способ рендера

Unity поддерживает различные способы рендеринга. Вы должны выбрать один из них, в зависимости от содержимого вашей игры и целевой платформы / аппаратного обеспечения. Различные методы рендеринга поддерживают различные возможности и дают различную производительность, особенно в аспекте применения теней и источников света. Метод рендеринга, используемый в вашем проекте, выбирается в Player Settings. Дополнительно свой метод рендеринга может быть выбран для каждой камеры.

Solid Color

Любые пустые части экрана будут отображать текущий фоновый цвет (Background Color ) камеры.

Только глубина

Если вы хотите рисовать оружие игрока не подвергая его обрезке объектами окружения, внутри которых оно находится, установите одну камеру, рисующей окружение, с Depth 0, и ещё одну камеру, рисующую оружие - Depth 1. Для камеры оружия выберите Clear Flags depth only . Это позволит отобразить окружение на экране, но проигнорировать всю информацию о взаимном положении предметов в пространстве. Когда оружие будет отрисовано, непрозрачные части будут полностью отрисованы на экране поверх ранее находившегося там изображения, независимо от того, насколько близко оружие находится к стене.


Не очищать

В этом режиме не очищаются ни цвет, ни буфер глубины. В результате каждый кадр рисуется поверх другого, из-за чего получится эффект размытия. Это обычно не используется в играх, и лучше использовать вместе с пользовательским шейдером.

Clip Planes (Плоскости отреза)

Near и Far Clip Plane - свойства, определяющие, где начинается и заканчивается область отрисовки камеры. Эта область ограничивается плоскостями, перпендикулярными направлению камеры, и находившимися в этих позициях относительно неё. Near Plane - это ближайшая позиция, а Far Plane - дальняя позиция.

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

Обратите внимание, что эти плоскости вместе определяют поле зрения камеры, которое известно как фрустум . Unity гарантирует, что объекты, полностью находящиеся за пределами фрустума, не будут отображаться. Это называется Frustum Culling и это срабатывает независимо от Occlusion Culling.

Из соображений производительности вы можете прекращать отрисовку мелких объектов раньше, чем отрисовку прочих. Для этого поместите их в separate layer и настройте дистанцию обрезки для этого слоя, используя функцию Camera.layerCullDistances .

Маска отрезания

Culling Mask используется для выборочного рендеринга групп объектов посредством использования слоёв. Больше информации об использовании слоёв можно найти .

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

Для того, чтобы интерфейс отрисовывался поверх изображений с других камер, нужно установить Clear Flags в значение Depth only и выставить камере интерфейса значение Depth выше, чем у прочих камер.

Normalized Viewport Rectangle

Normalized Viewport Rectangles предназначено для определения части экрана, на которой будет отрисовано изображение с камеры. Вы можете, к примеру, вставить изображение карты в нижний правый угол экрана, а вид с камеры на выпущенной ракете - в верхний левый угол. Немного поработав над дизайном, используя Viewport Rectangle , вы сможете создать кое-какие уникальные системы.

Очень просто создать раздельный экран для двух игроков, используя Normalized Viewport Rectangle . После создания двух камер, установите обеим камерам свойство H в значение 0.5 и для одной из них свойство Y в значение 0.5, а для другой - в значение 0. В результате, первая камера будет рисовать изображение в верхней половине экрана, а вторая камера - в нижней половине экрана.


Orthographic

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

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



Текстура рендера

Эта возможность доступна лишь в расширенных лицензиях Unity. Она позволяет отрисовывать изображенеи с камеры в текстуру (Texture), которая может быть применена к другому игровому объекту. Это делает простым создание спортивной арены с видеомониторами, камеры наблюдения, отражений и т.д.


  • Камеры могут быть вызваны, назначены дочерним объектом и заскриптованы как любой другой игровой объект
  • Для эффекта ускорения в гоночной игры используйте повышенный Field of View .
  • Камеры можно использовать в симуляции физики, если к ним добавить компонент Rigidbody .
  • Нет ограничения на количество камер в сцене.
  • Ортографические камеры отлично подходят для создания 3D пользовательских интерфейсов
  • Если вы наблюдаете артефакты глубины (мелькают близкорасположенные поверхности), попробуйте выставить Near Plane в максимально возможное значение.
  • Камеры не могут рендерить одновременно на экран и в Render Texture, только в одно из них.
  • Pro-лицензия предоставляет функцию названную Render-to-Texture, которая позволяет рендерить камеру в текстуру, для еще более уникальных эффектов.
  • Unity поставляется с предустановленными скриптами для управления камерой, их можно найти в Components->Camera Control . Поэкспериментируйте с ними чтобы узнать об их возможностях.

Справочник по камерам

В различных двухмерных игрушках, особенно в платформерах, многие могли замечать, что в разных игровых областях, камера ведет себя по-разному. В том смысле, что в определенной области, на камеру налагаются определенные ограничения движения. Например, в узком туннеле, камера может двигаться за героем только влево или вправо, но как только герой прыгает, допустим, в шахту, то там камера уже двигается только вверх или низ. Иначе говоря, нам нужно, чтобы мы могли в разных игровых зонах, создавать ограничения для камеры, за приделы которых она не может выходить.


Итак, как это работает. С помощью обычных спрайтов, мы обозначаем игровые зоны, камера может двигаться только внутри конкретного спрайта. Для перехода из одной зоны в другую, мы используем обычные триггеры, то есть, триггер просто определяет для камеры границы.

С начало обозначаем области:

А затем, ставим триггеры, который их переключают:


Тут важно помнить, что когда мы спрайтами создали зоны для камеры, эти объекты нельзя отключать и нельзя отключать компонент SpriteRenderer, чтобы скрыть спрайты, просто делам их прозрачными.

Теперь, скрипт который вешаем на камеру:

Using System.Collections; using UnityEngine; public class Camera2D: MonoBehaviour { private float smooth = 2.5f; private Vector3 min, max; private Camera cam; private Transform player; private static Camera2D _internal; private SpriteRenderer bounds; void Awake() { _internal = this; cam = GetComponent(); FindPlayer_internal(); } public static void FindPlayer() { _internal.FindPlayer_internal(); } public static void CalculateBounds(SpriteRenderer ren) { _internal.CalculateBounds_internal(ren); } void FindPlayer_internal() { player = GameObject.FindGameObjectWithTag("Player").transform; if(player != null) transform.position = new Vector3(player.position.x, player.position.y, transform.position.z); } void Follow() { Vector3 position = player.position; position.z = transform.position.z; position = MoveInside(position, new Vector3(min.x, min.y, position.z), new Vector3(max.x, max.y, position.z)); transform.position = Vector3.Lerp(transform.position, position, smooth * Time.deltaTime); } void LateUpdate() { if(player != null) { Follow(); } } public void CalculateBounds_internal(SpriteRenderer ren) { bounds = ren; float height = cam.orthographicSize * 2; Bounds b = new Bounds(Vector3.zero, new Vector3(height * cam.aspect, height, 0)); min = b.max + ren.bounds.min; max = b.min + ren.bounds.max; } Vector3 MoveInside(Vector3 current, Vector3 pMin, Vector3 pMax) { if(bounds == null) return current; current = Vector3.Max(current, pMin); current = Vector3.Min(current, pMax); return current; } }
И скрипт для триггера:

Using System.Collections; using UnityEngine; public class Camera2DTrigger: MonoBehaviour { private SpriteRenderer bounds; void OnTriggerEnter2D(Collider2D other) { Camera2D.CalculateBounds(bounds); } }
Как видно из примера, сложностей тут особых нет. Главное, правильно сделать зоны перехода. Если делать области внахлест, как показано на видео, то это будет оптимальным решением, переходы будут плавными.

Скачать демо проект.