Пишем арканоид на Unity. Добавление звуков и новых уровней


Оглавление (нажмите, чтобы открыть):

2D игра на Unity. Подробное руководство. Часть 6

Ищем звуки для нашей игры

Начнем подыскивать звуковый файлы для нашей игры. Самое главное — сохраняйте все свои звуки в несжатом 8bit .wav формате. В дальнейшем, в самом Unity можно будет сжать звук, не изменяя исходного .wav файла. Вот, что мы можем сделать:

  • Купить мелодию.
  • Попросить знакомого музыканта.
  • Использовать бесплатные звуки из звуковых банков (например, FindSounds or Freesound).
  • Записать звук самому.

С музыкой немного сложнее, но тоже все решаемо:

  • На сайте Jamendo много музыки разных музыкальных направлений. Будьте осторожны с лицензиями для коммерческих целей.
  • Иногда любители выкладывают свою музыку на рутрекере.
  • Воспользуйтесь продуктом Bosca Ceoil от Терри Кавана для создания своей, неповторимой мелодии.

Итак, создайте или найдите звуки взрыва и выстрела. Если вам лень, вы можете использовать эти:

Мы будем использовать один из треков игры «Больное бумажное приключение», Спинтроник для этого урока:

Импорт звука в Unity

Переместите 4 звуковые дорожки в папку «Sounds». Убедитесь, что для каждой из во вкладке «Инспектор» отключен «3D звук» (так как мы делаем 2D игру) и нажата кнопка «Применить». Вот и все.

Для воспроизведения музыки, просто перетащите песню во вкладку «Иерархия» (Hierarchy). Мы приглашаем Вас:

  1. Переименуйте новый игровой объект в «Музыка».
  2. Поместите его на (0, 0, 0) .

Обратите внимание на флажок «Mute». Это может вам пригодиться в ваших тестах. Со звуками придется повозиться, поскольку они должны проигрываться в определенное время. Для решения этой задачи напишем новый скрипт под названием «SoundEffectsHelper»:

Добавьте этот скрипт в игровой объект и заполните его поля со звуковыми клипами:

  1. SoundEffectsHelper.Instance.MakeExplosionSound(); в «HealthScript», только после воздействия частиц.
  2. SoundEffectsHelper.Instance.MakePlayerShotSound(); в «PlayerScript», сразу после weapon.Attack(false); .
  3. SoundEffectsHelper.Instance.MakeEnemyShotSound(); в «EnemyScript», сразу после weapon.Attack(true); .

Запустите игру и прислушайтесь. Да, у нас теперь есть звуки и музыка!

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

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

Меню — загрузка и перезапуск игры

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

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

Это наши фон и логотип. Импортируйте их в проект. Вы можете поместить их в «Меню» — подпапку «Текстуры». В противном случае «фон» сотрет предыдущий файл игры. Для кнопок мы будем использовать стандартные (уродливые) кнопки Unity.

Главное меню

Настало время создать сцену с главным меню. Это то, что показывается юзеру при запуске игры. Для начала, создайте новую сцену:

  1. «File» -> «New scene».
  2. Сохраните ее в папке «Scenes» как «Menu».

Вы можете также нажать cmd+N (OS X) или ctrl+N (Windows).

Наше главное меню будет состоять из:

  • Фона.
  • Логотипа.
  • Скрипта, который будет отображать кнопки.
  1. Создайте новый спрайт.
  2. Установите его в (0, 0, 1) .
  3. Задайте размер (2, 2, 1) .
  1. Создайте новый спрайт.
  2. Установите его в (0, 2, 0)
  3. Задайте размер (0.75, 0.75, 1)

Вот, что у вас должно получиться:

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

Теперь мы добавим кнопку «начать игру» с помощью скрипта. Создать скрипт по имени «MenuScript» в папке «Scripts», и приложите его к новому пустому игровому объекту под названием «Scripts»:

О синтаксисе можете подробнее почитать здесь GUI.Button.

Мы просто рисуем кнопку, которая будет загружать сценe «Stage1», когда игрок нажимает на нее.

Метод OnGUI применяется в каждом кадре и вставляет весь код, в котором отображен элемент GUI: полоса жизни, меню, интерфейс и т.д. Объект GUI позволяет нам быстро создать компоненты GUI из кода, как кнопка с методом GUI.Button .

Теперь запустите игру и полюбуйтесь нашим замечательным меню:

Жмем и. Катастрофа!

То, что нам нужно сделать четко написано в сообщении об ошибке.

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

Нажмите в меню Unity на «File», затем на «Build Settings»:

Теперь перетащите все сцены, которые должны быть в вашей игре. Здесь все просто: это «Меню» и «Stage1».

Вернитесь в меню. Нажмите на кнопку и . играть!

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

Для этих случаев в Unity есть метод DontDestroyOnLoad(aGameObject) . Просто примените его к игровому объекту – и он не исчезнет при загрузке новой сцены. Он вообще не исчезнет. Поэтому если в следующей сцене вам понадобится его убрать, придется уничтожать его вручную.

Наконец, мы позволим игроку начать игру сначала после того, как его персонаж умер. И, как вы, возможно, заметили, заметили происходит достаточно часто. Давайте «упростим» игру. Вот, что у нас сейчас происходит:

  1. Игрок попадает под пули.
  2. HealthScript.OnCollisionEnter запускается.
  3. Игрок теряет 1 единицу здоровья.
  4. «HealthScript» уничтожае игрока, так как у него меньше, чем 1 единица здоровья.

Мы добавим два новых действия:

  1. Вызывается PlayerScript.OnDestroy .
  2. Создается «GameOverScript» и добавляется к сцене.

Создайте в папке «Scripts» новый скрипт по имени «GameOverScript». Это маленький кусочек кода, который будет отображать кнопки «Начать сначала» и «Назад в меню»:

Это абсолютно идентично первому скрипту, который мы написали, с двумя кнопками.

Теперь, в «PlayerScript», нам нужно привязать этот новый скрипт к смерти:

Запустите игру и попытайтесь умереть (это не должно занять много времени):

Вы можете найти скрипт где-то на сцене:

Конечно, вы можете улучшить скрипт, например, добавив в него счет или анимациИ.

Если вы хотите провернуть что-нибудь эдакое, можете создать «GUI Skin».

Вы можете изменить интерфейс в «Inspector», чтобы сделать игру более интересной. Убедитесь в том, что этот скин лежит в папке «Resources» (Ресурсы).

Папка «Resources» занимает в Unity особое место. Чтобы загрузить ее содержимое, используйте метод Resources.Load() . Так вы получите возможность добавлять объекты прямо во время игры, и эти объекты могут быть созданы самими пользователями (как насчет модов?).

Тем не менее, скин не применяется до тех пор, пока вы не вызовите его в вашем скрипте. Во всех наших предыдущих сценариях GUI, мы должны загрузить скин только один раз, а не в каждом кадре, используя GUI.skin = Resources.Load («GUISkin»); .

Вот пример в «MenuScript» (проследите, как действует метод Start() ):

Как видите, нам пришлось изрядно попотеть чтобы сделать банальное неанимированное меню. Мы только что узнали как сделать меню для нашей игры. Поздравляем, вы только что сделали полноценный игровой продукт! Но, к сожалению, эта игра только на вашем компьютере. Чтобы продать ее, мы должны заявить о ней миру. Это как раз то, о чем мы будем говорить с вами в следующем уроке по Unity.

Большое количество уровней в арканоиде

16.09.2015, 20:40

Сила мяча в Арканоиде
Здравствуйте! Нужна помощь с механикой мяча в Арканоиде. Дело в том, что когда мяч падает, он.

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

200 vlozhennyx funkcij rabotaut kak chasy. Dal’she ne proveryal. Kod.

Определить количество уровней в TreeView
Как мне узнать, сколько уровней узлов есть в TreeView?

Требуется определить количество уровней дерева
Подскажите пожалуйста как можно определить количество уровней дерева Приведу код: public.

17.09.2015, 15:16 2 18.09.2015, 08:07 3 19.09.2015, 01:19 4 22.09.2015, 15:56 5

Вы ошибаетесь, здесь гораздо больше вариантов. То, что вы предлагаете, является худшей практикой, и делать так категорически нельзя. Я говорю это не чтобы подколоть или задеть как-то, просто я делал так же раньше, и наблюдал объемные утечки памяти в пустоту.
Если 50 уровней арканоида будут загружаться через App.LoadScene, ну кто угодно устанет ждать. А если новые уровни появятся? Всех их заносить в билд? А как удобно среди них ориентироваться в иерархии — слов нет! Короче, не вариант.


«Хватит болтать», скажете вы, и будете правы. Я тут не нотации пришел читать, а предлагать решение. То, что у меня есть — это ScriptableObject, универсальный объект для хранения данных. Его не нужно держать на сцене, на него можно делать прямые ссылки и обращаться к тому, что в нем хранится. А храниться может все подряд — префабы, вектора, данные любого типа (см. скриншот).

Игровой движок Unity 3D. Курс обучения

3. Простейшая игра. Оформление

3.7. Система частиц. Добавление спецэффектов в игру

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

Инструмент для создания спецэффектов – это система частиц. Она состоит из двух типов объектов: источник частиц и сами частицы. Частицы – это небольшие объекты, которые живут в игре строго ограниченное время. Примеры частиц: брызги воды, языки пламени в огне, клубы дыма. Источники частиц постоянно создают всё новые и новые частицы, взамен старых исчезнувших, они определяют все характеристики этих частиц.

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

1. В главном меню выбираем строчку «GameObject | Particle System» для создания объекта-источника. Меняем имя объекта на «Explosion».

2. Объект после создания сразу же начнёт работать и показывать свою анимацию. Настраиваем анимацию частиц по своему:

— В свойствах объекта в разделе «Particle System» в строчке «Duration» (продолжительность) ставим значение «1.00».

— В свойствах в строчке «Start Lifetime» нажимаем на треугольник справа, во всплывающем меню выбираем значение «Random Between Two Constants». Снизу ставим значения «» и «1» (частицы будут появляться с размером от 0 до 1). В строчке «Start Size» выставляем «случайное число» от «» до «5».

— В строчке «Start Color» выбираем вариант «Gradient». Кликаем на цвет, в левом углу выбираем желтый цвет (255, 255, 0), в правом углу — красный (220, 20, 20). В обоих верхних углах проставляем альфа-канал (200). Такой градиентный цвет будет похож на огонь.

— Открываем раздел «Emission» (излучение) меняем строчку «Rate» на значение «200». Это определяет, сколько частиц будет появляться за отрезок времени.

— В разделе «Shape» меняем значение строчки «Shape» на значение «Sphere» (чтобы частицы разлетались по кругу во все стороны) и выставляем «Radius» на «0.15». Включаем опцию «Random Direction».

— Возвращаемся в первый раздел «Explosion» меняем «Simulation Space» на «World».

— Убираем галочку «Looping», чтобы анимация не повторялась постоянно. Делаем это в последнюю очередь, потому что после выключения повторения мы не сможем видеть анимацию на предпросмотре.

3. Все настройки завершены. Теперь перетаскиваем созданный объект в папку «Prefabs». После этого удаляем сам объект с игровой сцены.

4. Редактируем скрипт «EnemyScript». В перечислении переменных добавляем строчку:

// Анимация при уничтожении объекта
public Transform explosion;

Ниже, в описании функции CollisionEnter2D после строчки «if (health if (health // Срабатывает при уничтожении объекта
if(explosion);
<
GameObject exploder = ((Transform)Instantiate(explosion, this.transform.position, this.transform.rotation)).gameObject;
Destroy(exploder, 2.0f);
>
Destroy (this.gameObject);

5. Сохраняем изменения в скрипте. Возвращаемся в Юнити, выбираем префаб «enemy», в его свойствах находим «Enemy Script» — «Explosion». Перетаскиваем префаб «Explosion» в найденную переменную «Explosion».

6. Запускаем игру, смотрим результат. теперь при уничтожении каждого врага должны появляться светлые частицы, разлетающиеся в разные стороны.

3.8. Добавление в игру звуковых эффектов и музыки

Ещё один способ украсить свою игру – добавить звуковые эффекты. Собственно говоря, в современных играх звук и музыка должны быть в обязательном порядке. Посмотрим, как звуки добавляются в Юнити.

Звуки можно создавать в специальных программах или просто записывать микрофоном. Для коротких звуков хорошо использовать звуковые файлы типа .ogg. Но вообще, создание звуков и музыки – это отдельная глубокая тема, которую мы не будем здесь затрагивать. В нашей игре мы используем бесплатный готовый набор звуковых эффектов из популярной игры «Counter Strike» и самодельную музыку.

Звуковые файлы
Game_SpaceWar
g_bounce.wav — попадание
explode4.wav — взрыв
fiveseven.wav — выстрел
Space_Battle_2.mp3 — фоновая музыка
Размер файла: 1,86 Mb

Создадим звук попадания во врага.

1. В папке проекта выбираем префаб «enemy» в его свойствах добавляем новый компонент «Component | Audio | Audio Source». Внутри компонента открываем настройки «3D Sound Settings», изменяем строчку «Volume Rolloff» — «Min Distance» на значение «10».

(В Юнити по умолчанию настроено панорамирование звуков, для лучшего результата. Но в данном случае в 2D-игре это будет лишним, поэтому мы и изменили настройку).

2. Редактируем скрипт «EnemyScript», в нём создаём новую переменную:

// Переменная для звука во время попадания лазера
public AudioClip hitSound;

Чуть ниже, в теле функции «CollisionEnter2D» после строчки «Destroy(theCollision.gameobject)» добавляем строчку:

3. Переменную для звука мы создали, условие, при котором звук срабатывает, тоже указали. Теперь нам нужен сам звук. Перетаскиваем звуковой файл «g_bounce.wav» в окно Юнити в папку «Sounds».

4. Выбираем префаб «enemy», в его свойствах в разделе «EnemyScript» перетаскиваем звуковой файл в переменную «hitSound».

Можем запустить игру, теперь каждое наше попадание по врагу будет сопровождаться выбранным звуком.

Создадим звук взрыва врага.

1. Выбираем префаб «Explosion», создаём для него компонент «Audio Source», так же как и в первый раз, ставим минимальную дистанцию «10». В этом компоненте в строчке «Audio Clip» выбираем звуковой файл взрыва «explode4.wav».

2. Для того, чтобы срабатывал этот звук, нам даже не нужно писать программный код. Звук будет включатся автоматически при появлении спецэффекта взрыва, за счёт включенной опции «Play On Awake» (играть при появлении).

3. Громкость определенного звука можно уменьшить с помощью настройки «Volume». Уменьшаем громкость взрыва до «0.3».

Теперь запускаем игру, уничтожаем врага, при этом слышим звук взрыва.

Создадим звук выстрела лазером.

1. Выбираем объект «playerShip», добавляем к нему компонент «Audio Source». В свойствах «3D Sound Settings» выставляем «Volume Rolloff» — «Min Distance» на «10».

2. Редактируем скрипт «PlayerScript», создаём новую переменную:

// Переменная для звука выстрела лазером
public AudioClip shootSound;

После строчки, где мы создаём лазер, добавляем:

3. Возвращаемся в юнити, в объекте «playerShip» в компоненте «PlayerScript» в строчке «Shoot Sound» выбираем аудио-файл «fiveseven.wav». Громкость звука лучше уменьшить до «0.2». Слушаем, как звучат выстрелы в игре. (Не самый подходящий звук для лазера, но лучше в CS и не найти).

Создадим фоновую музыку для игры.

1. В иерархии слева выбираем объект «Main Camera» (этот объект очень удобен для расположения музыки, ведь он всегда находится в центре экрана). В этом объекте добавляем компонент «Audio Source». Меняем «Audio Clip» на значение «Space_Battle_2.mp3» (это моя собственносочинённая музыка, можете вставить вместо неё другую музыку). Включаем опцию «Loop» для постоянного повторения музыки. Выставляем громкость «Volume» на «0.5».

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

Готовый проект с игрой
Game_SpaceWar_v0.3
2D Shooter
Для открытия игры в юнити: в папке «Assets» запускаем файл «Level_1.unity»
(Файлы для версии Unity 5.0.1)
Размер файла: 3,7 Mb

3.9. Создание текста на игровом экране

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

1. На вкладке «Иерархия» нажимаем клавишу «Create» и выбираем строчку «Create Empty». Выбираем созданный пустой объект, добавляем к нему свойство экранного текста – в инспекторе нажимаем «Add Component | Rendering | GUIText».

2. В иерархии меняем стандартное название объекта «GameObject» на более осмысленное «Score Counter» (Счетчик очков).

В свойствах объекта меняем значение строчки «Text» на «Очки: 0».

На игровой сцене (Scene) мы не увидим добавленный объект, его можно увидеть только на игровом виде — вкладка «Game».

3. В строчке «Position — Transform» ставим значение (0,1,0), чтобы поставить надпись в левый верхний угол.

Объект «Gui Text» привязан не к координатам игрового мира, а к координатам игрового экрана GUI. Но здесь мы проставили не координаты, а один из вариантов положения:

0, 1 — левый верхний угол экрана 1, 1 — правый верхний угол экрана
0, 0 — левый нижний угол экрана 1, 0 — правый нижний угол экрана

Третья цифра означает глубину – на каком слое размещается текст, позади или перед другим текстом.

4. Расположение текста в самом углу нас не устраивает, это некрасиво, нужно немного отодвинуть его от краёв. Для этого проставляем в свойстве «Pixel Offset» значение (10, -10). Вот здесь мы используем обычную систему координат в пикселях, и можем точно определить положение текста.

5. Теперь установим подходящий шрифт для текста. Лучше пока оставим в качестве шрифта «Font» стандартный «Arial». А размер «Font Size» установим «25». (На экране предпросмотра текст выглядит крупно, но он не масштабируется, и в полноэкранном режиме будет точно таким же, а все остальные игровые элементы увеличатся).

6. Копируем объект «Score Counter»: выбираем его в иерархии, нажимаем правой кнопкой мыши, кликаем по строчке «Duplicate».

7. Новый текстовой объект назовём «Waves Counter». В его свойстве «Text» напишем «Волна: 0».

Размещаем его в правом верхнем углу – в «Position» ставим координаты (1,1,0).

Дополнительно в строчке «Anchor» выбираем значение «Upper right», чтобы текст не просто был расположен в углу, а ещё и был сориентирован относительно этого угла (Иначе придётся смещать текст влево от угла не на -10 пикселей, а на — (10 + ширина самого текста). Так точно не нужно заморачиваться, ведь ширина текста может поменяться прямо во время игры).

В «Pixel Offset» пишем значение (-10, -10).

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

Открываем скрипт «GameController». Внутри в разделе переменных добавляем новые строчки.

// Переменные для вывода на экран
private int score = 0;
private int waveNumber = 0;

// Ссылки на текстовые объекты
public GUIText scoreText;
public GUIText waveText;

9. Внизу пишем новую функцию «Увеличение счета»:

public void IncreaseScore(int increase)
<
score += increase;
scoreText.text = «Очки: » + score;
>

Заметьте, здесь у нас не обычная функция-процедура, где мы всегда после названия ставили пустые скобки «IncreaseScore ()», а полноценная функция, поэтому в скобках мы объявляем новую переменную для этой функции — int increase. В переменной «increase» у нас будет задано количество очков, которое нужно прибавить.

Оператор «+ =» берёт старое значение, прибавляет к нему указанное число и сохраняет на месте старого числа. В полной форме это выражение выглядит так: score = score + increase.

В последней строчке мы обновляем наш текстовой объект на экране, и он показывает нам новое значение количества очков.

10. Созданную функцию мы будем запускать из совершенно другого места. Открываем скрипт «EnemyScript». За последней строчкой «controller.KilledEnemy ()» добавляем новую строчку:

Именно здесь, при вызове функции, мы и определяем, сколько очков получит игрок за уничтожение врага, прописав в скобках цифру «10».

11. Для подсчета волн врагов делаем следующее. Возвращаемся в скрипт «GameController». После строчки «if (currentNumberOfEnemies waveNumber++;
waveText.text = «Волна: » + waveNumber;

Оператор «++» (инкремент) увеличивает переменную на одну единицу. В полной форме это выражение выглядит так: waveNumber = waveNumber + 1. (Сайт GamesIsArt.ru)

12. Сохраняем все файлы скриптов. В иерархии выбираем объект «GameController», в инспекторе в переменные «scoreText» и «waveText» перетаскиваем наши текстовые объекты «Score Counter» и «Waves Counter», чтобы создать связь между ними.

Запускаем игру. Тестируем, как обновляется текст на экране.

3.10. Публикация игры


Улучшать игру мы можем до бесконечности, но пока давайте займёмся её публикацией хотя бы в таком виде.

1. В главном меню Юнити выбираем «File | Build Settings». Здесь мы можем выбрать, какие игровые сцены добавить в конечную сборку. Нажимаем кнопку «Add Current». (Пока у нас всего одна сцена, так что вариантов нет).

2. Ниже можно выбрать, для какой игровой платформы мы публикуем игру. В Юнити доступны все самые популярные платформы: компьютер, консоли, мобильные устройства, браузеры. Для начала выберем «Windows – x86».

3. Нажимаем клавишу «Build And Run». В новом меню выбираем название для игры «Game», сохраняем и ждём. Если компиляция пройдёт успешно, перед нами появится меню параметров экрана для запуска игры. Выбираем развертку экрана и запускаем игру, нажав «Play».

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

Unity3D: может ли один AudioSource воспроизводить несколько звуков одновременно?

Привет всем!
Экспериментирую со звуком в unity. Возникла ситуация, когда обьект ударяется, нужно воспроизвести звук. Так вот, в чем проблема: звук играется достаточно долго. Не успевает он закончить воспроизводиться, как новое воспроизведение звука прерывает старое. В итоге звук обрывается.
Меня интересует может ли AudioSource воспроизводить несколько звуков?
Как вообще решается данная проблема?
У меня пока одна мысль: нужно каждый раз при воспроизведении создавать обьект с AudioSource, назначить ему звук и все будет хорошо.
Но может это слишком ресурсзатратно? Есть другие варианты?

.PlayOneShot(clip); //опционально можно указать уровень громкости вторым параметром

SlavaLia
> .PlayOneShot(clip); //опционально можно указать уровень громкости вторым параметром
Это мне известно. Мне нужно в один момент времени запустить более 1 аудиоклипа.
Есть вариант сделать несколько AudioSources:
http://answers.unity3d.com/questions/175995/can-i-play-multiple-a… gameobje.html

AudioSource.PlayAudioClipAtPosition
но лучше самому сделать свой вариант

Alerr
> Это мне известно. Мне нужно в один момент времени запустить более 1 аудиоклипа.

Так именно это и может делать функция .PlayOneShot(clip);
Она запускает звучание нового клипа и не останавливает звучание ранее запущенного клипа.

Скорее всего вы путаете её с функций .Play() — вот она то как раз использует аудио соурс в монопольном режиме.

Проверил только что у себя.
Код тестовый прилагается.
Две музыкальные композиции звучат одновременно.
Ч.Я.Д,Н.Т?

Скрипт на движение 2d персонажа в unity3d. Пишем арканоид на Unity. Механика мяча и платформы

Public GameObject player;
public int speed = 5;

Теперь укажем в методе старта, что это объект, на котором висит скрипт.

Void Start () <
player = (GameObject)this.gameObject;
>

Теперь сделаем само передвижение игрока вперёд при нажатии на «W» или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
>

Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>

Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на «A» или «D».
Я буду использовать «Rotate()». Чтобы поворачивать по оси «Y», я буду использовать «up» и «down». Кстати, для этого ещё надо объявить переменную «public int speedRotation = 3». И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>

Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в «Window» => «Animation». В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;

Теперь в старте добавим клип.

Теперь мы будем его воспроизводить через «CrossFade». Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.

Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации «public AnimationClip anima2;»? так же добавим и переменной «public int jumpSpeed = 50;». И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Всё. Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour <
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Vo courier new font-size: text-align: justify> player = (GameObject)this.gameObject;
animation.AddClip(anima, «animCube»);
>
void Update() <
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade(«animCube»);
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

(Вы можете нажать на галочку чекбокса, чтобы отключить его. Вы можете щелкнуть правой кнопкой мыши на компоненте, чтобы вернуть прежнее свойство, удалить его и т.д.

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

Последний компонент, необходимый для добавления на нашего игрока: «Rigidbody 2D». Это поможет физическому движку правильно задействовать объект в игровом пространстве. Более того, это позволит вам использовать столкновения в скрипте.

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

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

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

По умолчанию в скрипте уже прописаны методы Start и Update . Вот краткий список наиболее часто используемых функций:

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

В скрипт для нашего игрока мы добавим несколько простых элементов управления, а именно: клавиши со стрелками, которые будут перемещать корабль.

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.


Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

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

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

Введение:

1. Шаг

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

public float speed;

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

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

public class PlayerMove: MonoBehaviour <

public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

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

public class PlayerMove: MonoBehaviour <

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown («Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>

Выберите крысу. В скрипте PlayerMove появилась новая переменная для обозначения направления взгляда. Включите её, так как крыса смотрит налево.

Крыса может теперь бежать влево и вправо и менять направление взгляда. Вы можете проверить сцену.

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

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

void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.


12. Шаг

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

public class PlayerAnim: MonoBehaviour <

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool («isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat («speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat («speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool («isJumping» , true );
>
>

Можете проверить сцену.

13. Step

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

//ссылочная переменная для звукового файла
public AudioClip footsteps;

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

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

public class PlayerSound: MonoBehaviour <

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

Скачать готовый проект

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

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

Для того, чтобы сдвинуть платформу, нам потребуется два вида информации: позиция и скорость.

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

Вот то, что у нас должно получиться в итоге:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.


Вот, как это можно сделать:

Как вы могли заметить, сила прилагается не строго вертикальная, а наклоненная вправо — шарик будет двигаться по диагонали.

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

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

В следующей части

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

C# и еще 7 языков для Unity

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

Такое мнение относительно C# в Unity — не пустой слух. Помимо того, что это относительно простой и производительный язык программирования, есть и исключительно аппаратная причина. Unity использует open-source проект Mono, который является одной из многочисленных реализаций платформы Microsoft. NET. По факту, все библиотеки Unity написаны на C#.

Так что использовать все возможности платформы, не зная C#, у вас не получится. Но это не означает, что нельзя ограничиться базовым уровнем языка. Напротив, движок Unity тем и хорош, что здесь основными могут быть несколько языков — в зависимости от задач и разработчика. Но C# необходим. К счастью, его довольно легко изучить, а применять можно далеко за пределами Unity.

JavaScript

UnityScript был вторым базовым языком платформы. Вы можете убедиться в этом, открыв описания скриптов, где коды даны как на C#, так и на UnityScript. Если вам знаком и симпатичен синтаксис JavaScript — вам понравится работать с Unity.

Но будет ошибкой полагать, что UnityScript — это тот же JavaScript, но с другим названием. К примеру, US поддерживает классы, но при этом в нем нельзя переназначать переменные и использовать необязательные точки с запятой.

Плохая новость в том, что с лета 2020 года разработчики усиленно искореняют UnityScript из платформы. Это не ограничивается прекращением поддержки в оболочке — создатели пакетов со скриптами получают предупреждения о необходимости перевести весь код в C#.

К счастью, есть компилятор на GitHub, который все еще позволяет работать с JavaScript в Unity, и эту лазейку никто не собирается закрывать. Но удовольствие определенно потеряно.

Продолжая тему языков, от которых отказались разработчики Unity, вспомним Boo. По структуре он похож на Python, прост в освоении, у него краткий и удобный синтаксис, который поддерживается .NET и Mono. В Unity он появился благодаря одному из создателей платформы — Родриго Де Оливейре, который также разработал Boo.

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

IronPython и IronRuby

Для любителей Python все же есть возможность поработать с Unity. Решение — IronPython, набор библиотек, расположенных в GitHub. Позволяет запускать «змеиные» скрипты прямо из C#-кода. Полезное расширение — возможность вызывать .NET-библиотеки из Python.

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

Lua не входит в топ самых популярных языков программирования. Но он обитает преимущественно в играх, так что в Unity должен быть представлен. За это отвечает MoonSharp — интерпретатор для Mono, платформы .NET и Unity. MoonSharp не заменяет C#, а дает разработчику возможность подключить сторонний код на Lua. Такой принцип реализован, к примеру, в WoW, где огромное количество модов написано именно на Lua.

Как и в подавляющем большинстве продуктов, где требуется быстродействие, определенный фронт работ поручают C или C++. Unity не требует установки дополнительных надстроек или подключения библиотек, здесь «из коробки» можно создавать DLL-плагины.

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

Чтобы повысить скорость обработки информации, в Unity можно использовать другой язык — Rust. Функции и методы напрямую писать не получится, но их можно вызвать из Unity-кода. Пик популярности Rust позади, но, по свежим рейтингам, до 1,5 % программистов периодически используют его в работе. И им эта функция Unity наверняка придется по душе.

Как видите, несмотря на необходимость знать C# хотя бы на базовом уровне, Unity позволяет использовать еще несколько разношерстных языков. Если захотите разнообразить свою работу в гейм-дизайне, вы теперь знаете, как это сделать.

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

Такое мнение относительно C# в Unity — не пустой слух. Помимо того, что это относительно простой и производительный язык программирования, есть и исключительно аппаратная причина. Unity использует open-source проект Mono, который является одной из многочисленных реализаций платформы Microsoft. NET. По факту, все библиотеки Unity написаны на C#.

Так что использовать все возможности платформы, не зная C#, у вас не получится. Но это не означает, что нельзя ограничиться базовым уровнем языка. Напротив, движок Unity тем и хорош, что здесь основными могут быть несколько языков — в зависимости от задач и разработчика. Но C# необходим. К счастью, его довольно легко изучить, а применять можно далеко за пределами Unity.

JavaScript

UnityScript был вторым базовым языком платформы. Вы можете убедиться в этом, открыв описания скриптов, где коды даны как на C#, так и на UnityScript. Если вам знаком и симпатичен синтаксис JavaScript — вам понравится работать с Unity.

Но будет ошибкой полагать, что UnityScript — это тот же JavaScript, но с другим названием. К примеру, US поддерживает классы, но при этом в нем нельзя переназначать переменные и использовать необязательные точки с запятой.

Плохая новость в том, что с лета 2020 года разработчики усиленно искореняют UnityScript из платформы. Это не ограничивается прекращением поддержки в оболочке — создатели пакетов со скриптами получают предупреждения о необходимости перевести весь код в C#.

К счастью, есть компилятор на GitHub, который все еще позволяет работать с JavaScript в Unity, и эту лазейку никто не собирается закрывать. Но удовольствие определенно потеряно.

Продолжая тему языков, от которых отказались разработчики Unity, вспомним Boo. По структуре он похож на Python, прост в освоении, у него краткий и удобный синтаксис, который поддерживается .NET и Mono. В Unity он появился благодаря одному из создателей платформы — Родриго Де Оливейре, который также разработал Boo.

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

IronPython и IronRuby

Для любителей Python все же есть возможность поработать с Unity. Решение — IronPython, набор библиотек, расположенных в GitHub. Позволяет запускать «змеиные» скрипты прямо из C#-кода. Полезное расширение — возможность вызывать .NET-библиотеки из Python.

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

Lua не входит в топ самых популярных языков программирования. Но он обитает преимущественно в играх, так что в Unity должен быть представлен. За это отвечает MoonSharp — интерпретатор для Mono, платформы .NET и Unity. MoonSharp не заменяет C#, а дает разработчику возможность подключить сторонний код на Lua. Такой принцип реализован, к примеру, в WoW, где огромное количество модов написано именно на Lua.

Как и в подавляющем большинстве продуктов, где требуется быстродействие, определенный фронт работ поручают C или C++. Unity не требует установки дополнительных надстроек или подключения библиотек, здесь «из коробки» можно создавать DLL-плагины.

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

Чтобы повысить скорость обработки информации, в Unity можно использовать другой язык — Rust. Функции и методы напрямую писать не получится, но их можно вызвать из Unity-кода. Пик популярности Rust позади, но, по свежим рейтингам, до 1,5 % программистов периодически используют его в работе. И им эта функция Unity наверняка придется по душе.

Как видите, несмотря на необходимость знать C# хотя бы на базовом уровне, Unity позволяет использовать еще несколько разношерстных языков. Если захотите разнообразить свою работу в гейм-дизайне, вы теперь знаете, как это сделать.

Audio Source

Audio Source (источник звука) воспроизводит Audio Clip в сцене. Если Audio Clip является 3D клипом, источник проигрывается в заданном положении в пространстве и будет приглушаться в зависимости от расстояния. Аудио может быть распределено по колонкам (например, из стерео в 7.1) с помощью свойства Spread и трансформироваться между 3D и 2D с помощью свойства PanLevel. Можно контролировать зависимость этих эффектов от расстояния с помощью кривых затухания. Также если слушатель находится в одной или нескольких зонах реверберации, то к источнику применяются реверберации (только для Unity Pro). Для обогащения аудио ряда, к источнику можно применять отдельные аудио фильтры. См. справку по аудио эффектам для дополнительной информации.

Свойства

Свойство: Функция:
Audio Clip Ссылка на аудио клип для проигрывания этим источником.
Output The sound can be output through an audio listener or an audio mixer.
Mute Если включено, звук всё ещё будет проигрываться, но не будет слышен.
Bypass Effects Для быстрого пропуска всех эффектов, применённых к источнику звука. Простой путь включения/отключения всех эффектов.
Bypass Listener Effects Для быстрого включения/отключения всех эффектов, применённых к слушателю.
Bypass Reverb Zones Для быстрого включения/отключения всех зон реверберации.
Play On Awake Если включено, звук начнёт воспроизводиться сразу после загрузки сцены. Если отключено, вам потребуется запустить звук программно, с помощью метода Play() .
Loop Включите для бесконечного повтора Audio Clip ’а после его окончания.
Priority Определяет приоритет данного источника звука среди всех остальных источников в сцене (0 = наиболее важный, 256 = наименее важный, 128 по умолчанию). Используйте 0 для музыки, чтобы избежать её случайного переключения.
Volume Насколько громок звук на расстоянии одной мировой единицы измерения (одного метра) от слушателя ( Audio Listener ’а).
Pitch Степень изменения высоты тона при замедлении/ускорении Audio Clip ’а. Величина 1 означает нормальную скорость воспроизведения.
Stereo Pan Sets the position in the stereo field of 2D sounds.
Spatial Blend Устанавливает степень влияния 3D движка на источник звука.
Reverb Zone Mix Sets the amount of the output signal that gets routed to the reverb zones. The amount is linear in the (0 — 1) range, but allows for a 10 dB amplification in the (1 — 1.1) range which can be useful to achieve the effect of near-field and distant sounds.
3D Sound Settings Settings that are applied proportionally to the Spatial Blend parameter.
Doppler Level Определяет количество эффекта доплера, применяемого к данному источнику (при значении 0 эффект применяться не будет).
Spread Устанавливает угол распространения для 3d стерео или мультиканального звука в пространстве динамиков.
Min Distance Громкость звука будет максимальной, насколько это возможно, на протяжении MinDistance. Вне MinDistance она будет постепенно снижаться. Увеличьте MinDistance звука, чтобы сделать его “громче” в трёхмерном мире; снизьте, чтобы сделать звук “тише” в трёхмерном мире.
Max Distance Расстояние, на котором звук перестаёт затухать. За пределами этой точки его громкость останется на уровне, на котором она была бы на расстоянии MaxDistance единиц от слушателя и больше не будет затухать.
Rolloff Mode Как быстро звук угасает. Чем выше значение, там ближе должен быть слушатель к звуку прежде, чем его можно будет услышать (определяется по графику).
— Logarithmic Rolloff Громкость звука высока, когда вы близко к источнику, но при удалении от объекта она довольно быстро падает.
— Linear Rolloff Чем вы дальше от источника звука, тем хуже вы его слышите.
— Custom Rolloff Звук источника аудио ведёт себя соответственно графику затуханий.

Типы спадания

Существует три типа спадания (Rolloff Mode): Logarithmic Rolloff (логарифмическое спадание), Linear Rolloff (линейное спадание) и Custom Rolloff (пользовательское спадание). Custom Rolloff настраивается с помощью кривой зависимости громкости от расстояния, как описано ниже. Если вы попытаетесь изменить кривую в то время, как у вас выбран тип Logarithmic или Linear, то он автоматически сменится на Custom Rolloff.

Типы спадания источника звука.

Функции расстояния

Существует несколько свойств аудио, которые могут меняться по функции расстояния между источником и слушателем звука.

Volume (громкость): Амплитуда (0.0 — 1.0).

Spatial Blend: 2D (original channel mapping) to 3D (all channels downmixed to mono and attenuated according to distance and direction).

Spread (распространение): Угол (в градусах, 0.0 — 360.0).

Low-Pass (только если к источнику добавлен LowPassFilter): Частота отсекания (22000.0–10.0).

Reverb Zone: Amount of signal routed to the reverb zones. Note that the volume property and distance and directional attenuation are applied to the signal first and therefore affect both the direct and reverberated signals.

Функции расстояния свойств источника Volume, Pan, Spread и свойства Low-Pass аудио фильтра. На графике отмечено текущее расстояние до слушателя.

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

Создание источников звука

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

Для создания нового источника звука:

  1. Импортируйте ваши аудио файлы в Unity проект. Теперь они — аудио клипы.
  2. Вызовите пункт GameObject->Create Empty из строки меню.
  3. При выделенном, только что созданном GameObject’е, выберите пункт меню Component->Audio->Audio Source .
  4. В инспекторе назначьте свойство Audio Clip компонента Audio Source.

Важно: Если вы хотите создать Audio Source только для одного Audio Clip ’а, который находится в папке Assets вашего проекта, то вы можете просто перетащить клип в окно сцены — GameObject с компонентом Audio Source для вашего клипа будет создан автоматически. Перетаскивание клипа на существующий GameObject добавит на него клип вместе с новым Audio Source , если этого компонента там ещё нет. Если на объекте уже есть компонент Audio Source , тогда новый клип, который вы перетащили, заменит тот, который уже используется источником звука.

Как создать простую 2D-игру на Unity

На создание игры обычно уходит много времени и сил, но если воспользоваться движком Unity, можно значительно ускорить процесс.

Unity — это движок для создания игр в 2D и 3D. Он позволяет в несколько раз ускорить разработку, потому что берет на себя огромную часть задач программиста:

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

  • Outlast;
  • Hearthstone;
  • Cuphead;
  • Rust;
  • Firewatch;
  • Inside;
  • Cities: Skylines и другие.


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

Из этой статьи вы узнаете, из каких компонентов создается игра и как написать свой первый проект.

Как установить Unity

Скачать Unity можно на официальном сайте. Новичкам будет достаточно бесплатного тарифа “Personal”.

Важный момент! Последняя версия движка, которую предлагается скачать по умолчанию, может не поддерживаться на старых компьютерах; подходящую под возможности вашего компьютера версию стоит поискать в архиве версий. Игра для этой статьи написана на Unity 5.5.0f3. Интерфейс более поздних версий не сильно менялся, поэтому это руководство подойдет и для них.

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

Запустите установщик и следуйте инструкциям. Кроме самого движка, вам предложат установить Microsoft Visual Studio — интегрированную среду разработки. Она предоставляет лучшие возможности по работе со скриптами в Unity, но занимает много места на диске.

Если она уже установлена или если используется другой редактор кода, уберите галочку. Альтернативами могут быть Microsoft Visual Studio Code (более легкая версия Visual Studio) или MonoDevelop — встроенный редактор Unity.

Когда установка завершится, пора приступать к разработке своей первой игры.

Как создать проект в Unity

Для начала запустите Unity и нажмите кнопку New или New project.

codedokode / Задание про Арканоид.md

Задача про Арканоид

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

Предлагаю тебе сделать свой небольшой аналог арканоида при помощи Javascript и Canvas.

  • Нужные знания: основы javascript, основы HTML
  • Уровень сложности: начинающий
  • Время: 2-3 недели

HTML — это язык разметки текста, на котором пишут веб-страницы, которые можно просматривать в браузере. Канвас — это HTML-элемент, который можно поместить на страницу и на котором можно рисовать изображения с помощью яваскрипта. Если ты с ним не знаком, начни со статьи http://habrahabr.ru/post/111308/

Если по ходу решения задачи у тебя будут сложности с яваскриптом — теорию можно почитать на http://learn.javascript.ru

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

ООП в яваскрипте

В JS нет полноценного ООП, но есть его имитация на прототипах (да, придется с ними разбираться). Почитать можно тут: http://learn.javascript.ru/prototype

Вот пример 2 классов, Parent и Child который от него наследуется:

Код функции inherit ты можешь написать сам: в новых браузерах используя Object.create() , в старых — примерно такую функцию:

Мы, естественно, будем использовать ООП, а не писать лапшу из функций и переменных. Для хранения информации об находящихся на поле предметах удобно использовать объекты. Нам понадобятся такие классы:

  • бита (Bat) (свойства: координаты, размер)
  • шарик (Ball) (свойства: координаты, угол движения, скорость движения)
  • кирпичик (Brick) (свойства: координаты)

У объектов этих классов есть общие черты:

  • они помещены на игровое поле
  • они имеют координаты и размеры (и некоторые могут двигаться)
  • они участвуют в столкновениях и реагируют на них
  • они рисуются

Значит, стоит унаследовать классы Bat, Ball, Brick от базового класса, например, GameItem. Мы также создадим в них методы:

  • render(ctx) — отрисовывает объект на канвасе
  • move(dt) — будет вызываться, чтобы движущийся объект обновил свои координаты. Неподвижные объекты в этом методе ничего не делают.
  • onCollisionWithBall(ball) — будет вызываться при ударе об объект шариком (например, пробиваемый с 2 ударов кирпичик увеличит счетчик ударов, а пробиваемый с первого раза — исчезнет). Это мы пока оставим на потом.

Кроме этих классов, нам понадобится еще один, который будет реализовывать игровую логику (создавать объекты, дивгать их, давать им команду на отрисовку). Назовем его GameLoop. Если со временем в нем накопится слишком много кода, придется разбить его на несколько классов.

Загрузка карты уровня

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

Код загрузки (его можно сделать методом loadMap() в классе GameLoop) должен на основе такой карты создавать массив объектов-кирпичиков с нужными координатами.

Шарик и биту можно создать вручную в нужных координатах (в оригинальной игре шарик неподвижен до первого движения биты). Их вполне можно хранить как свойства в классе GameLoop.

Общая логика игры

  • загрузка уровня
  • создание биты и шарика
  • запуск главного цикла

В играх обычно используется архитектура в виде game loop — бесконечного цикла, который выполняется все время, пока идет игра. Вот примерная последовательность действий в нем:

  • сбор информации о нажатых клавишах
  • перемещение автоматически двигающихся объектов (шарик) с проверкой столкновений
  • перемещение управляемых игроком объектов (бита) с проверкой столкновений
  • если игрок проиграл или выиграл, выход из цикла
  • перерисовка экрана
  • (возможно пауза для ограничения fps)
  • переход к началу цикла

Как ты видишь, на каждом шаге игрового цикла происходит перерисовка экрана, и число выполненных шагов в секунду совпадает с fps (числом кадров в секунду). Поскольку монитор обновляется с какой-то фиксированной частотой (для LCD это обычно 60 Гц что соответствует 16 мс на кадр), в конце цикла иногда делают паузу, если он выполнился слишком быстро, так как обновлять картинку в видеобуфере быстрее, чем обновляется монитор, нет смысла. Это называется ограничение fps.

В браузере создать вечный цикл не получится: браузер блокируется на то время, пока выполняется скрипт, потому тут используют другой подход: мы создаем таймер, который срабатывает 60 раз в секунду и вызывает нашу функцию (в котороый мы делаем все вышеперечисленные действия, после чего возвращаем управление браузеру). Такой таймер в старых браузерах делали с помощью setTimeout, но в новых браузерах есть кое-что получше: requestAnimationFrame()

Преимущества использования этой функции:

  • браузер ограничивает частоту вызова этой функции частотой обновления монитора (чаще 60 раз в секунду она твой код не вызвовет)
  • некоторые браузеры на некоторых платформах синхронизируют вызов кода с VSync (паузой между обновлением картинки на мониторе) и тем самым позволяют избежать от эффекта tearing ( http://en.wikipedia.org/wiki/Screen_tearing ). Увы, пока не везде.
  • если вкладка не видна на экране, браузер может снизить частоту вызова твоей функции до 1 раза в секунду (зачем перерисовывать картинку, которую пользователь все равно не увидит?)

Почитать про ее использование можно тут: http://habrahabr.ru/post/114358/

Заметь также, что наш код может по разным причинам вызываться с неравномерными интервалами. Если движущиеся объекты будут сдвигаться на одинаковое расстояние каждый раз, то в итоге движение может получиться дерганым — потому надо измерять время dt , прошедшее с момента последнего вызова нашей функции и рассчитывать на сколько за это время сдвинулся шарик.

Текущее время в миллисекундах можно получить с помощью var t = +new Date() (это короткая запись для var t = (new Date()).getTime() ).

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

Определение столкновений (collision detection)

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

Таким образом мы можем обойтись без сложных физических моделей.

Во многих играх экран перерисовывается полностью на каждом шаге игрового цикла. Но в этой игре, если подумать, большая часть игровой области остается неизменной: движутся лишь бита и шарик, и иногда исчезают кирпичики. Логично было бы не греть зря процессор, а завести так называемый dirty regions list — список изменившихся областей экрана, который формируется при движении или изменении объектов, и перерисовывать только указанные в нем части экрана.

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

Анимация и эффекты

Было бы неплохо, если кирпичики исчезали не резко, а плавно, а непробиваемые кирпичики вспыхивали при ударе. Для анимации стоит завести отдельные классы: AnimatedEffect, представляющий собой одну анимацию одного объекта и AnimationList, класс, который существует в одном экземпляре, содержит список выполняющихся эффектов и вызывает их с нужной частотой. Анимация также должна добавлять затронутые регионы в dirty list.

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

  • стартовый экран
  • экран проигрыша
  • экран победы

И сделать логику перехода между ними и игровым циклам.

Стоит поместить все функции, классы, переменные игры в один неймспейс, например, Arcanoid, таким образом:

Было бы неплохо подсчитывать очки и сохранять рекорд на сервер, но как проверить, что злодей не отсылает подделанные цифры? Один из вариантов — записывать на клиентской стороне полный лог (все действия и события с временем) игры и проверять на сервере его на правильность. Его конечно, тоже можно подделать, но гораздо сложнее чем просто поменять цифры.

Не хочешь попробовать добавить игру по сети?

Пишем арканоид на Unity. Механика мяча и платформы

Всем привет. Продолжаем дело, начатое в первой части. Сейчас у нас есть платформа и стоящий на ней персонаж с анимацией покоя. Настало время научить нашего персонажа бегать вправо-влево по платформе.

Загрузим сцену из первой части. Напомню, что в прошлый раз мы импортировали несколько спрайтов в папку AssetsSprites . На всякий случай, внизу поста еще раз приведу ссылку на спрайты. Среди них должен быть спрайт под названием Run . Мы будем использовать его для создания анимации бега. Для этого нам надо проделать те же действия по превращению одиночного спрайта в коллекцию, как и при создании анимации покоя. Вкратце напомню: выделяем спрайт, в окне Inspector устанавливаем свойство Sprite Mode как Multiple , нажимаем ниже Sprite Editor , нарезаем изображение в режиме Grid или Automatic .

Теперь в окне Hierarchy выбираем Character и переходим в окно Animation . Нажимаем на поле с анимацией Idle и выбираем Create New Clip , чтобы создать анимацию бега. Сохраним файл анимации в папке AssetsAnimations под именем Run .

Новая созданная анимация Run стала текущей в окне Animation . Разворачиваем спрайт Run в окне Project , выделяем все фалы Run_0… Run_9 и перетаскиваем в окно Animation . Установим пока значение Sample равное 24.

Все это мы уже делали в первой части, а теперь будет нечто новое. Перейдем в окно Animator . Сейчас там отображены три анимации: Any State , Idle и Run . Нам предстоит задать условия перехода из анимации Idle в анимацию Run , то есть из состояния покоя в состояние бега. В нижнем левом углу есть поле Parameters . Нажимаем на плюсик, выбираем Float и называем новый параметр как Speed . Тем самым мы создали параметр типа число с плавающей запятой, обозначающий скорость перемещения персонажа. Именно в зависимости от значения этого параметра будет происходить переключение из анимации покоя в анимацию бега. Теперь нажимаем правой кнопкой мыши на анимацию Idle , выбираем Make Transition и нажимаем левой кнопкой мыши на анимацию Run . Между анимациями появится линия со стрелкой. Передвиньте мышкой прямоугольники анимации, если плохо видно. Кликнем по линии со стрелкой. В окне Inspector отобразятся свойства перехода между анимациями. Обратим внимание на низ окна, в раздел Conditions . Кликнем на параметр Exit Time и поменяем его на Speed . Второе поле Greater оставим без изменений, а в третьем введем значение 0.01 . Мы создали условие перехода из анимации покоя в анимацию бега — оно происходит, когда значение параметра скорости становится немногим больше нуля.

Теперь нужно сделать обратный переход — из Run в Idle . Делаем все с точностью наоборот: Make Transition от Run к Idle , выделяем переход, в Conditions устанавливаем SpeedLess0.01 .

Теперь у нас есть две анимации и условия перехода между ними. Но пока ничего работать не будет, потому что все что мы сделали нужно «оживить» при помощи скрипта. Давайте перейдем в окно Project и создадим в папке Assets подпапку Scripts . Добавим в нее новый C# Script , назовем его CharacterControllerScript и откроем на редактирование.

Я приведу полный листинг скрипта с подробными комментариями, а ниже еще поясню, что в нем происходит.
using UnityEngine; using System.Collections; public > /// Начальная инициализация /// private vo > /// Выполняем действия в методе FixedUpdate, т. к. в компоненте Animator персонажа /// выставлено значение Animate Physics = true и анимация синхронизируется с расчетами физики /// private vo , Mathf.Abs(move)); //обращаемся к компоненту персонажа Rig > 0 && !isFacingRight) //отражаем персонажа вправо Flip(); //обратная ситуация. отражаем персонажа влево else if (move /// Метод для смены направления движения персонажа и его зеркального отражения /// private vo >

Итак, мы завели несколько переменных: для задания максимальной скорости перемещения, для определения направления (вправо/влево) и для работы с компонентом Animator . Почти все действия происходят в методе FixedUpdate . В нем мы получаем значение оси Х , которое меняется при нажатии на клавиатуре клавиш влево-вправо или A-D (если не меняли соответствующие настройки проекта!). Затем устанавливаем это значение параметру Speed компонента Animator . Обратите внимание, что мы берем модуль этого значения при помощи метода Mathf.Abs , так как при создании условий перехода между анимациями покоя и бега мы сравниваем значение параметра с положительным числом 0.01 . Нам здесь не важно, в какую сторону бежит персонаж. Важно лишь величина значения. Далее задаем скорость перемещения по оси Х в соответствии со значением максимальной скорости. И, наконец, проверяем, в какую сторону бежит персонаж, и в какую сторону он в этот момент повернут. Если он бежит вправо, а повернут влево — разворачиваем его вправо путем инвертирования его размера по оси Х . И наоборот. Этим нехитрым способом мы избавились от необходимости делать две анимации вместо одной: для бега вправо и для бега влево.

Сохраняем скрипт. В Unity перетаскиваем его на нашего Character в окне Hierarchy . Запускаем игру, нажимаем влево-вправо или A-D.

Капитан Коготь теперь умеет бегать! Скорость анимации получилась быстроватой. Ее можно снизить путем уменьшения значения Sample в окне Animation для анимации Run (значение 12 будет нормально). Если одновременно с игрой у вас видно окно Animator , то вы увидите, что во время покоя работает анимация Idle (бегает синий прогрессбар), а во время бега происходит переход на анимацию Run , и, соответственно, работает она.


На этом пока все. Нам осталось разобраться с прыжками… и узнать при этом еще несколько новых вещей!

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

Вот список всех статей:

Где мы остановились?

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

Превью результата

Движение платформы

Сама платформа у нас уже есть — мы ее создали еще в прошлом уроке. Осталось научить ее двигаться, причем исключительно влево или вправо, т.е. по оси X. Для этого нам потребуется написать сценарий (Script ).

Сценарии представляют собой фрагменты программного кода, которые ответственны за какую-то конкретную задачу. Unity может работать со скриптами, написанными на трех языках программирования: Boo, JavaScript и C#. Мы будем использовать последний, но вы можете попробовать свои силы и с другими языками.

Итак, для создания скрипта перейдем на вкладку Project , найдем там одноименную папку Scripts и кликнем на нее правой кнопкой мыши. Выберем Create -> C# Script . Появится новый файл с названием NewBehaviourScript . Переименуйте его в PlayerScript для удобства. На вкладке Inspector вы можете видеть содержимое скрипта.

Двойным кликом откройте скрипт. Запуститься среда разработки MonoDevelop, которую вы впоследствии можете изменить на любой удобный для вас редактор. Вот то, что вы увидите:

Using UnityEngine; using System.Collections; public class NewBehaviourScript: MonoBehaviour < // используйте этот метод для инициализации void Start () < >// Update вызывается при отрисовке каждого кадра игры void Update () < >>

Все сценарии на Unity имеют по умолчанию два метода:

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

Для того, чтобы сдвинуть платформу, нам потребуется два вида информации: позиция и скорость.

Таким образом, необходимо создать две переменные для сохранения этой информации:

public float playerVelocity;
private Vector3 playerPosition;

Обратите внимание, что одна переменная объявлена публично, а вторая — приватно. Для чего это делается? Дело в том, что Unity позволяет редактировать значения публичных переменных не переходя в редактор MonoDevelop, без необходимости изменения кода. Эта возможность очень полезна в тех случаях. когда необходимо «на лету» корректировать какое-то значение. Скорость платформы — одно из таких значений, и именно поэтому мы объявили его публично.

Сохраните сценарий в редакторе MonoDevelop и перейдите в редактор Unity. Теперь у нас есть сценарий и нам нужно присвоить его какому то объекту, в нашем случае — платформе. Выберите нашу платформу во вкладке Hierarchy и в окне Inspector добавьте компонент, кликнув на кнопку Add Component .

Добавление нашего скрипта в компонент можно сделать и по-другому. Перетащите наш сценарий в область кнопки Add Component . Во вкладке Inspector вы должны увидеть что-то подобное:

Обратите внимание, что в компоненте скрипта появилось поле Player Velocity , которое можно тут же изменить. Это получилось возможным благодаря публичному объявлению переменной. Установите параметр в значение 0.3 и перейдите в редактор MonoDevelop.

Теперь нам надо узнать позицию платформы: playerPosition . Для того, чтобы инициализировать переменную, следует обратиться к объекту сценария в методе Start() :

// используйте этот метод для инициализации vo >

Отлично, мы определили начальную позицию платформы, и теперь можно ее двигать. Так как нам надо, чтобы платформа перемещалась только по оси X, то мы сможем использовать метод GetAxis класса Input . Этой функции мы передадим строку Horizontal , и она вернет нам 1, если была нажата клавиша «вправо», и -1 — «влево». Умножив полученное число на скорость и прибавив эту величину к текущей позиции игрока, мы и получим движение.

Также добавим проверку на выход из приложения по нажатию на клавишу Esc .

Вот то, что у нас должно получиться в итоге:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; > >

Сохраните скрипт и вернитесь в редактор Unity. Нажмите кнопку Play и попробуйте передвинуть платформу при помощи кнопок «влево» и «вправо».

Определение игровой области

Вы, скорее всего, заметили, что платформа может двигаться и за пределами игрового поля. Дело в том, что у нас нет никаких проверок на выход за пределы каких-то границ.

Давайте добавим в наш существующий скрипт еще одну публичную переменную и назовем его boundary .

Эта переменная будет хранить максимальную координату платформы по оси X. Так как мы собираемся строить уровни в симметричной форме вокруг точки с координатами (0, 0, 0), то абсолютное значение переменной boundary будет одинаковым и для положительной части оси X, и для отрицательной.

А теперь добавим пару условий. Поступим достаточно просто: если вычисленная нами позиция будет больше boundary или меньше -boundary , то мы просто зададим новую позицию по оси X, равную значению переменной boundary . Таким образом, мы гарантируем, что платформа не уедет за пределы наших границ и никогда не покинет игровую зону. Вот код:

Using UnityEngine; using System.Collections; public ) * playerVelocity; // выход из игры if (Input.GetKeyDown(KeyCode.Escape)) < Application.Quit(); >// обновим позицию платформы transform.position = playerPosition; // проверка выхода за границы if (playerPosition.x boundary) < transform.position = new Vector3(boundary, playerPosition.y, playerPosition.z); >> >

Теперь вернитесь в редактор и, переключаясь в игру, найдите оптимальное значение переменной boundary . В нашем случае подошло число 5.46. Откройте Inspector и сбросьте позицию платформы по оси X на 0, а параметр Boundary выставьте согласно найденному вами значению.

Нажмите кнопку Play и убедитесь в том, что вы все сделали правильно. Платформа должна двигаться только в пределах игрового поля.

Включение физики

Чтобы столкновения были более реалистичные — воспользуемся симуляцией физики. В этой статье мы добавим физические свойства мячику, платформе и границам поля. Так как мы пишем 2D игру, то будем использовать 2D коллайдеры. Коллайдер — это отдельный тип компонентов, который позволяет объекту реагировать на коллайдеры других объектов.

В окне Hierarchy выберем нашу платформу, перейдем в Inspector и нажмем на кнопку Add Component . В появившемся окошке наберем collider . Как вы можете увидеть — вариантов достаточно много. Каждый коллайдер имеет специфические свойства, соответствующие связанным объектам — прямоугольникам, кругам и т.д.

Так как наша платформа имеет прямоугольную форму, мы будем использовать Box Collider 2D . Выберите именно его, и компонент автоматически определит размеры платформы: вам не нужно будет задавать их вручную, Unity сделает это за вас.

Сделайте то же самое и для 3 границ (Hierarchy -> Inspector -> Add Component -> Box Collider 2D ).

С мячиком чуть-чуть по другому: он имеет круглую форму. Выберем мяч и добавим для нее компонент Circle Collider 2D .

На самом деле коллайдер окружности и прямоугольника очень похожи, за исключением того, что вместо параметра Size , определяющим ширину и длину, в окружности используется Radius . Объяснения здесь, думаем, излишни.

Упругое столкновение

Для того, чтобы наш мячик отскакивал от блоков, стен и платформы, нам следует задать поверхность (material) для физического компонента, добавленного ранее. В Unity все уже имеется, нам остается только добавить нужный материал.

Откройте окно Project и внутри папки Asset создайте новую папку под названием Physics . Кликните по только что созданной папке правой кнопкой мыши и выберите Create -> Physics2D Material . Задайте название BallPhysicsMaterial .

Каждая поверхность в Unity имеет два параметра: трение (friction) и упругость (bounciness) . Более подробно вы можете прочитать про физический движок и ряд физических параметров . Если вам требуется абсолютно упругое тело, то следует выставить трение на 0, а упругость на 1.

Сейчас у нас есть готовый материал, но он пока никак не связан с мячом. Выберите объект мяча во вкладке Hierarchy и в окне Inspector вы увидите поле Material компонента Circle Collider 2D . Перетащите сюда недавно созданный материал.

Добавление компонента Rigid Body

Для того, чтобы наш мячик двигался под контролем физики, мы должны добавить ему еще один компонент: Rigid Body 2D . Выберите объект мяча в окне Hierarchy и добавьте вышеупомянутый компонент — хоть он и имеет несколько параметров, нас интересует только один: Gravity Scale . Так как наш шарик будет двигаться только за счет отскоков, то мы зададим этому параметру 0 — таким образом мы гарантируем, что гравитация не будет реагировать на объект. Все остальное можно не менять.

Поведения шарика

Давайте создадим для шарика отдельный скрипт (снова воспользуемся C# в качестве языка программирования) и назовем его BallScript . Свяжите созданный скрипт с объект (Hierarchy -> Inspector -> Add Component ).

Перед тем, как начать писать скрипт, давайте определим поведение шарика:

  1. Шар имеет два состояния: неактивное (когда он в начале игры находится на платформе) и активное (когда находится в движении).
  2. Шар будет становиться активным только один раз.
  3. Когда шар становится активным, мы применяем к нему силу для того, что он начал движение.
  4. Если шар вышел за пределы игрового поля, он переводится в неактивное состояние и помещается на платформу.

Основываясь на этой информации, давайте создадим глобальные переменные ballIsActive , ballPosition и ballInitialForce:

private bool ballIsActive;
private Vector3 ballPosition;
private Vector2 ballInitialForce;

Теперь, когда у нас есть набор переменных, мы должны подготовить объект. В методе Start() мы должны:

  • создать силу, которая будет применена к шару;
  • перевести шар в неактивное состояние;
  • запомнить позицию шара.

Вот, как это можно сделать:

Как вы могли заметить, сила прилагается не строго вертикальная, а наклоненная вправо — шарик будет двигаться по диагонали.

Следующим шагом является проверка состояния шара, поскольку задать силу нам надо только в том случае, если шар находится в неактивном состоянии:

Если предположить, что мы находимся в начале игры, то мы должны применить силу к шару и установить его в активное состояние:

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

В методе Update мы должны проверять состояние шарика, и в случае если оно неактивное, нам надо задать позицию мячика по оси X таким же, какое оно у платформы.

Решение достаточно простое, но как нам получить координату совсем другого объекта? Элементарно — мы создадим переменную типа GameObject и сохраним ссылку на объект платформы:

public GameObject playerObject;

Вернемся к методу Update() :

Сохраните скрипт и вернитесь в редактор Unity. Вы наверняка заметили, что переменная playerObject объявлена, используется, но нигде не инициализирована. Да, так и есть. Чтобы ее проинициализировать, перейдите во вкладку Hierarchy , найдите шар и в окне Inspector найдите компонент Ball Script . У данного компонента есть параметр Player Object , в настоящее время пустующий:

Найдите во вкладке Hierarchy нашу платформу и перетащите ее на поле Player Object . Запустите игру, нажав кнопку Play , и убедитесь, что все работает.

Сброс игры

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

Это состояние отловить очень просто: шар будет активен, а его положение по оси Y отрицательно. Если это так, то мы переводим шар в неактивное состояние и ставим его на платформу:

If (ballIsActive && transform.position.y

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

В следующей части

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

Итак. Всем привет. И сегодня я расскажу, как сделать простое движение персонажа. Сейчас только от третьего лица. Приступим.
Начнём, пожалуй, с создания персоажа. У меня это будет куб. Кто не знает, как создавать кубы или круги, поясняю — «GameObject» => «CreateOther» => «Cube». Создаём таким же образом камеру и привязываем к кубу (то бишь просто в иерархии перетаскиваем камеру на куб).
Так. Теперь создадим поверхность, по которой персонаж будет ходить. Пусть это будет просто «Plane». Ах, да. В конце урока будет ссылка с исходником по туториалу для тех, кто не понял.
Итак. Теперь создадим скрипт «Move». Добавим переменную игрока и переменную скорости.

Public GameObject player;
public int speed = 5;

Теперь укажем в методе старта, что это объект, на котором висит скрипт.


Void Start () <
player = (GameObject)this.gameObject;
>

Теперь сделаем само передвижение игрока вперёд при нажатии на «W» или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
>

Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>

Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на «A» или «D».
Я буду использовать «Rotate()». Чтобы поворачивать по оси «Y», я буду использовать «up» и «down». Кстати, для этого ещё надо объявить переменную «public int speedRotation = 3». И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>

Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в «Window» => «Animation». В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;

Теперь в старте добавим клип.

Теперь мы будем его воспроизводить через «CrossFade». Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.

Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации «public AnimationClip anima2;»? так же добавим и переменной «public int jumpSpeed = 50;». И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

Всё. Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour <
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Vo courier new font-size: text-align: justify> player = (GameObject)this.gameObject;
animation.AddClip(anima, «animCube»);
>
void Update() <
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade(«animCube»);
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

Создание объекта, контролируемого игроком, требует наличия определенных элементов: спрайт, способ управления им и способ его взаимодействия с игровым миром. Рассмотрим этот процесс шаг за шагом и начнем, пожалуй, со спрайта. Вот изображение, которое мы будем использовать:

  1. Скорируйте картинку в папку «Textures»
  2. Создайте новый спрайт и назовите его «Player»
  3. Настройте спрайт так, чтобы он отображался в свойстве «Sprite» компонента «Sprite Renderer»

Если у вас возникли проблемы, обратитесь к предыдущему уроку. Мы проделали точно такие же действия для фона и «реквизита».

  1. Поместите игрока в слой «2 — Foreground»
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте «Sprite Renderer». Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели «Инспектор».

По умолчанию пустой объект игры выглядит так:

Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.

(Вы можете нажать на галочку чекбокса, чтобы отключить его. Вы можете щелкнуть правой кнопкой мыши на компоненте, чтобы вернуть прежнее свойство, удалить его и т.д.

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку «Добавить компонент» объекта игрока. Выберите «Box Collider 2D». Вы можете увидеть коллайдер в редакторе «Сцена» зрения и настройки его размера в «Инспекторе» в поле «Размер» (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:

В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью «Circle Collider 2D». Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!

2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity «Полигоннальный коллайдер 2D» (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

«Polygon Collider 2D» похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме «Scene». Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

Последний компонент, необходимый для добавления на нашего игрока: «Rigidbody 2D». Это поможет физическому движку правильно задействовать объект в игровом пространстве. Более того, это позволит вам использовать столкновения в скрипте.

  1. Выберите объект Player в «Hierarchy».
  2. Добавьте компонент «Rigidbody 2D».

Теперь, нажмите кнопку «играть» и смотрите, что у нас вышло:

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

По-умолчанию, ускорние свободного падения в Unity равно 9.81 , т.е. мы имеем дело с земной гравитацией.

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите «гравитационный масштаб» равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке «Fixed Angles», чтобы предотвратить вращение корабля, обусловленное такой физикой.

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке «Scripts» и назовите это «PlayerScript». Откройте ваш любимый редактор или используйте подменю «Sync» (нажмите на «Assets» в строке меню, затем на «Sync MonoDevelop Project») для правки созданного Unity скрипта.

«Sync MonoDevelop Project» : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

По умолчанию в скрипте уже прописаны методы Start и Update . Вот краткий список наиболее часто используемых функций:

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the «Inspector»).
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой («RigidBody» и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой «Trigger».
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как «Trigger».

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс «2D». Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом «2D».

В скрипт для нашего игрока мы добавим несколько простых элементов управления, а именно: клавиши со стрелками, которые будут перемещать корабль.

Using UnityEngine; /// /// Контроллер и поведение игрока /// public ); // 4 — движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); > vo >

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне «Инспектор». Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в «Edit» -> «Project Settings» -> «Input» . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 — движение вправо, -1 — влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.

Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель «Inspector», даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна «Проект» (Project) на игровой объект в «Иерархии» (Hierarchy). Вы также можете нажать на «Add Component» и добвить его вручную.

Нажмите кнопку «Play» в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент «Hello, World!» для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в «Инспекторе», и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе — это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

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

Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку «Textures».
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство «Масштаб» (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте «Box Collider 2D» размером (4, 4) .
  5. Add a «Rigidbody 2D» with a «Gravity Scale» of 0 and «Fixed Angles» ticked.

Сохраните префаб и. вуаля!

Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его «MoveScript».

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

Скопируем некоторые части кода, который мы написали в «PlayerScript» для движения персонажа. We will add another designer (a public member you can alter in the «Inspector») variable for the direction:

Прикрепите скрипт к осьминогу. Нажмите «Play» и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

Вы узнали, как добавить игрока, движущегося с помощью клавиатуры. Также, мы создали врага с зачаточным AI. Теперь мы хотим иметь возможность уничтожить его! А для этого, нам нужны боеприпасы, которые мы создадим в следующем уроке .

Введение:


1. Шаг

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

public float speed;

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

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

public class PlayerMove: MonoBehaviour <

public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

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

public class PlayerMove: MonoBehaviour <

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
>

//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown («Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>

void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis («Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>

Выберите крысу. В скрипте PlayerMove появилась новая переменная для обозначения направления взгляда. Включите её, так как крыса смотрит налево.

Крыса может теперь бежать влево и вправо и менять направление взгляда. Вы можете проверить сцену.

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

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

void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.

12. Шаг

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

public class PlayerAnim: MonoBehaviour <

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool («isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat («speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat («speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool («isJumping» , true );
>
>

Можете проверить сцену.

13. Step

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

//ссылочная переменная для звукового файла
public AudioClip footsteps;

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

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

public class PlayerSound: MonoBehaviour <

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).

Мастер Йода рекомендует:  О ключевом слове «this» языка JavaScript особенности использования с пояснениями
Добавить комментарий