Урок "Тумблеры"

От автора

Здравствуй, дорогой читатель. Вот и кончились экзамены, и пришло время отдыхать, поэтому я снова открываю Construct и начинаю писать серию уроков по созданию игр.

Меня часто спрашивают, почему мой первый урок «Платформер за 5 минут» называется именно так, ведь на его выполнение уходит не меньше двух, а то и трех часов. Отвечу — все дело в том, что этот самый пример платформера за 5 минут в Construct я собрал не более, чем за 5 минут. То есть, когда вы несколько раз выполните урок «Платформер за 5 минут» и запомните принцип построения событий для платформера, то при равных задачах вы тоже сможете создавать свои платформеры меньше, чем за 5 минут.

Об уроке. Сначала я хотел написать урок «TDS за 5 минут», но потом подумал, что людям, которые уже научились создавать простые платформеры, наверняка будет интересно почитать о чем-нибудь посложнее, что затрагивало бы более глубокие слои в самом формировании игровых событий. Поэтому я и решил сначала написать урок про «Тумблеры», так как эта тема кажется мне сейчас более актуальной, ну а после, конечно, сразу приступлю к созданию простой TDS игры.


Введение

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

Например, вам нужно сделать так, чтобы при нажатии на клавишу «F» ваша игра открывалась на полный экран, а повторное нажатие на эту же самую клавишу сворачивало ее обратно в окно. Также часто это требуется для того, чтобы поставить игру на Паузу или открыть инвентарь.

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

1. Мы создадим лампу, которая будет включаться и выключаться с помощью всего одной клавиши Space (Пробел). Это достаточно простой тумблер, который переключает события между собой.

2. Далее мы создадим вентилятор, который будет иметь 3 режима скорости вращения (1-выключен, 2-первая скорость, 3-вторая скорость). Вы будете кликать ЛКМ по кнопкам, и они будут осуществлять переключение между режимами.

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

Предостережение

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

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

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

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

Подготовка

Для начала скачайте архив material, который содержит в себе все необходимые спрайты, музыку и звуки для выполнения этого урока. Распакуйте архив и запускайте программу Construct. Создайте новый проект New DirectX Game, и приступим к настройке сцены.

Первым делом идем в Layout Properties (Свойства уровня) и задаем там размер экрана 800 по ширине и 600 по высоте. См. рис. 1

Рис. 1

Далее идем в свойства приложения и во вкладке Windows Properties (Свойства окна) выставляем те же значения, что и в свойствах уровня. См. рис. 2

Рис. 2

Теперь добавляем в сцену объект Mouse & Keyboard, и на этом подготовка сцены завершена. Переходим к расстановке спрайтов.

Декорации

Создаем объект спрайт, в него загружаем изображение background_light_off.png из папки sprites (эта папка находится в распакованном вами архиве material) и переименовываем его в background. Тут же добавляем в него второй кадр, загружаем туда файл с именем background_light_on.png. Теперь, для этого спрайта, настройте скорость анимации, она должна быть 0. См. рис. 3

Рис. 3

Итак, у нас есть первый спрайт с именем background, содержащий в себе 2 кадра анимации, воспроизводящиеся со скоростью 0. Теперь нам нужно его правильно разместить в сцене. Для этого в его свойствах во вкладке Common (Общие) найдите параметр X и впишите туда 400, а для параметра Y впишите значение 300. См. рис. 4

Рис. 4

Убедившись, что спрайт background находится ровно по центру окна, переходим на панель Layers (Слои) и, кликнув на замок (защита от выделения слоя), переименовываем первый слой в background. Далее кликнув по стрелке вверх, создаем еще один слой с именем foreground. См. рис. 5

Рис. 5

Для нового слоя создаем второй спрайт и загружаем в него изображение под названием blade.png. Заходим в свойства нового спрайта и переименовываем его в blade, ниже напротив X пишем 399, а Y — 378. Опускаемся еще ниже и заходим во вкладку Behaviors и назначаем поведение Rotate (Вращение). Напротив параметра Speed (Скорость) ставим значение 0. См. рис. 6.

Рис. 6

Итак, мы создали фон сцены и надели лопасти на вентилятор, теперь нам нужно поверх них надеть защитную решетку. Для этого на слое foreground создаем третий спрайт и загружаем в него изображение с именем frame.png. Переименовываем спрайт в frame и выставляем точно такую же позицию, как у спрайта blade (X 399, а Y 378). У вас должно получиться как на рисунке 7 (лопасти вентилятора должны быть за решеткой, а не впереди нее).

Рис. 7

Теперь к вентилятору нам нужно приклеить кнопки управления, для этого загружаем четвертый спрайт с изображением button_off.png. Далее идем в анимацию и загружаем для него второй кадр с изображением button_on.png. Скорость анимации, как и у спрайта background ставим на 0. Теперь идем в свойства и называем его button, далее выставляем первую позицию у первой кнопки (кнопок у вентилятора будет 3, поэтому у них будет 3 позиции). Напротив X ставим 368, напротив Y — 548. Затем ниже заходим во вкладку Private Variable добавляем приватное значение под именем select, тип значения выбираем Text, а само значение вписываем button1. См. рис. 8

Рис. 8

Теперь зажав клавишу Control, копируем кнопку и ставим ее на позицию X 400, а Y 550. Зайдя в свойства кнопки, во вкладке Private Variable, напротив select вписываем button2. То же проделываем еще раз для третьей кнопки, позиция которой должна быть X 432, Y 548, а значение select должно быть button3.

Итак, с помощью приватных значений мы разделили 3 копии одного объекта. Теперь нам нужно сделать так, чтобы первая кнопка была в нажатом состоянии, чтобы при запуске игры наш вентилятор был выключен. Для этого выделите первую кнопку (расположенную слева) и зайдя в ее свойства найдите вкладку Properties (Свойства) и напротив параметра Start Frame (Стартовый Кадр), вместо 1 впишите значение 2. См. рис. 9.

Рис. 9

В итоге у вас должно получиться как на рис. 10.

Рис. 10

В сцене у нас еще присутствует радио, но у него не хватает регулятора громкости, поэтому, на том же самом слое, где и кнопки (foreground), создаем пятый спрайт с изображением volumecontrol.png, в свойствах переименовываем его в volumecontrol и ставим на позицию X 601, а Y 510. У нас должно получиться как на рис. 11.

Рис. 11

Посмотрите на рис. 11 еще раз и присмотритесь к двум получившимся у нас кругам, которые выделяются из общей картины. Первый круг с надписью Fan расположен на сетке вентилятора, второй круг с надписью Radio, расположенный на приемнике. Вся проблема в том, что у обоих этих кругов отсутствуют тени и блики. Конечно, художник мог сразу нарисовать эти блики на спрайте, но что делать, если нам нужно, чтобы, например, при вращении регулятора громкости у радио, блик оставался на месте (не вращался вместе с ним), а при включении света автоматически менял свою позицию и отражал свет от лампы? Чтобы не создавать лишних кадров анимации, мы воспользуемся хитростью и создадим маску наложения, которая будет имитировать блик и меняться в зависимости от окружения.

Создайте новый слой с именем mask и поместите его в самый верх, чтобы он оказался нам двумя слоями ниже. См. рис. 12.

Рис. 12

Заходим в свойства слоя и в самом низу, во вкладке Layer Effects (Эффект Слоя), кликам по опции add. См. рис. 13.

Рис. 13

В открывшемся списке находим эффект под названием Overlay и кликнув по кнопке OK, применяем его к слою. Теперь, находясь на этом слое, создаем новый (шестой спрайт) с изображением mask.png. Переименовываем его в mask и выставляем ему позицию X 601, Y 510.

Зайдите в его свойства и во вкладке Common (Общие) в опции Opacity (Прозрачность) установите значение 75. Как видно из результата, наш регулятор немного преобразился и теперь выглядит более реалистично. См. рис. 14.

Рис. 14

Теперь нам необходимо создать точно такую же маску, но для вентилятора. Для этого скопируйте (не клонируйте) спрайт mask и задайте ему позицию X 399, а Y 380. Теперь вы наверняка заметите, что маска имеет размер чуть меньше, чем круг с надписью Fan, поэтому зайдите в свойства спрайта и сделайте ему размер чуть больше, вписав напротив Width (Ширина) и Height (Высота) значение 76.

Свет в окне исходит из правой верхней части экрана, поэтому и блик должен быть повернут в соответствии с источником. В свойствах, там же? где вы меняли ширину и высоту, чуть ниже, напротив опции Angle (Угол) поставьте значение 90. В итоге у вас должно получиться как на рис. 15.

Рис. 15

Сейчас маска, которая стоит у вентилятора имеет блик, отражающий свет из окна, но когда мы включим свет в комнате, этот блик должен быть также отражен и от лампы. К тому же он должен быть ярче, чем блик в окне. Чтобы это осуществить, нам потребуется разделить обе копии одного спрайта с помощью все тех же приватных значений. Выделяем спрайт mask (который установлен на регуляторе громкости радио) и, зайдя в его свойства, создаем для него приватное значение с именем select. Тип оставляем number, а в Initial вписываем значение 1. Теперь выделяем вторую копию спрайта mask (которая располагается на вентиляторе) и в свойствах, меняем приватное значение select на цифру 2. См. рис. 16.

Рис. 16

Теперь мы можем управлять отдельной копией спрайта mask через события, не затрагивая другую копию объекта. Далее, кликнув по команде Insert an object (Вставить объект) добавляем два объекта — Mouse & Keyboard и XAudio2.

Итак, мы загрузили все спрайты, объекты и подготовили сцену к ее оживлению, поэтому смело переходим в Event Sheet Editor (Редактор Событий).

События

Пора нам зажечь в комнате свет с помощью обычной лампы. Для начала создайте новую группу событий и назовите ее Light. В комментариях к группе можете написать все, что угодно. Я написал «Общий свет в комнате». См. рис. 17.

Рис. 17

Теперь справа на панели Project (Проект) создайте новое Глобальное значение с именем light. См. рис. 18.

Рис. 18

Возвращаемся обратно в группу Light и создаем новое событие:

Внимание! Процесс создания событий я буду описывать в упрощенном виде, так как подразумевается, что ранее вы уже читали документацию на сайте (уроки в разделе Быстрый старт, Интерфейс и События).

Итак, для условия мы выбираем объект Mouse & Keyboard и далее при единичном клике назначаем клавишу Space. В действии выбираем глобальное значение light и выписываем для него выражение global('light')=0:1. Это хитрое выражение, при обращении к которому оно меняет глобальное значение с 0 на 1 и наоборот. Таким образом, получается простое переключение глобального значения при каждом клике по клавише Space. В итоге первое событие должно выглядеть у вас как на рисунке 19.

Рис. 19

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

Для условия выбираем глобальное значение light, далее оставляем параметр Equal to (Равно) и ниже вписываем значение 0. В действии выбираем наш рисунок фона с названием Background и задаем ему первый кадр анимации Set animation frame > 1. Так мы определили, что когда глобальное значение light будет 0, то программа включит первый кадр для нашего фона, который по умолчанию должен быть с выключенным светом.

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

Кликнув по New action (Новое действие), выберите спрайт blade, далее выберите команду Set colour filter (Задать цвет фильтра) и из стандартной палитры установите для него темно-серый цвет. См. рис. 20.

Рис. 20

Далее точно такой же цвет задайте еще трем спрайтам — frame, volumecontrol и button. Помимо спрайтов в сцене еще есть 2 копии маски (для регулятора громкости радио и вентилятора), которые также должны быть темнее, если лампа в комнате выключена. Но в данном случае для затемнения спрайта мы будем использовать не цвет, а прозрачность.

Итак, для второго события добавляем еще одно действие:

Выберите спрайт mask и задайте ему Opacity (Прозрачность) равную 50. В итоге ваше событие должно выгладить как на рисунке 21.

Рис. 21

Таким образом, мы сделали так, что когда глобальное значение light равно 0, то все эти спрайты в комнате, в том числе и обе маски, окрашиваются в темно-серый цвет.

Теперь нам необходимо сделать так, чтобы при выключенной лампе блик на маске вентилятора был от окна. Для этого для события 2 мы создаем Под-Событие (не путайте со смежными событиями):

Для условия выбираем спрайт mask, далее находим приватное значение select и вписываем 2 (потому что ранее мы обозначили эту копию спрайта приватным значением 2). В действии для этого под-события выбираем все тот же спрайт mask и на этот раз задаем ему угол равный 90 градусам. Таким образом, мы создали событие, которое меняет угол копии с приватным значением 2. Если вы все сделали правильно, то ваше событие должно выглядеть как на рисунке 22.

Рис. 22

События (2 и 3), которые мы сейчас создали, определяют только то, что происходит, когда свет в комнате выключен. Теперь нам необходимо создать все тоже самое, но для ситуации, когда свет включен. Для этого мы копируем событие 2 (соответственно копируется и событие 3) и заменив в нем значение 0 на 1 в условии Is global variable ‘light’, меняем некоторые действия:

Для background: Set animation frame to 1 меняем значение на 2, чтобы при обращению к этому действию включался второй кадр анимации где свет в комнате включен.

Далее для спрайтов blade, frame, volumecontrol и button меняем цвет фильтра на чистый белый. Маску с прозрачностью 50 не трогаем, а вот в под-событии (оно должно быть у вас под номером 4) для маски нужно изменить угол с 90 на 0, чтобы при включенном свете блик был повернут в сторону горящей лампы. Если вы все сделали правильно, то у вас должно получиться как на рисунке 23.

Рис. 23

Запустите игру (кликнув по значку Run Layout (Запустить Уровень) на главной панели) и затем попробуйте понажимать на клавишу Space. Свет в комнате должен включаться и отключаться. Обратите внимание на маски, которые мы создали, и на то, как меняется блик у вентилятора.

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

Теперь мы переходим к созданию событий для вентилятора. Здесь их будет чуть больше, и они будут чуть сложнее, поэтому прошу быть очень внимательными и серьезно отнестись к каждой мелочи. И так, создаем новую группу и называем ее Fan. В комментариях пишем что угодно, я написал «Взаимодействие кнопок со скоростью вращения вентилятора». Далее создаем новое событие:

Для условия выбираем объект Mouse & Keyboard и далее команду On object clicked (Кликнуть один раз по объекту). Здесь оставляем левую кнопку мыши, а в качестве объекта выбираем спрайт button. Теперь перейдите на панель проекта и создайте новое Глобальное значение с именем state. Тип глобального значения должен быть text, а само значение по умолчанию: button1. См. рис. 24.

Рис. 24

Теперь для условия On Left Clicked on button (событие 6, которые мы создали), создаем действие.

Выбираем глобальное значение state и с помощью команды set value вписываем ему значение в виде выражения button.Value('select').

Объясню для чего это нужно. Дело в том, что у нас есть 3 копии одной кнопки button, и у каждой из этих копий есть приватное значение select, в которое мы в предыдущей главе сами вписали имена каждой из копий. Сейчас мы создали событие, что, когда мы кликаем по кнопке (любой из трех копий), то в глобальное значение state записывается имя этой копии из ее приватного значения. Сравните получившееся событие с рисунком 25.

Рис. 25

Создаем новое событие. Для условия выбираем спрайт button и сравниваем его приватное значение select с глобальным, вписав в поле Value выражение global('state'). В действии также выбираем спрайт button и в анимации задаем ему кадр 2. То есть в событии 7 мы сравниваем приватное значение select с глобальным (которое задается при клике мышью по объекту), и если оно соответствует имени одной из трех копий, то у нее включается кадр 2, и оказывается нажатой кнопкой.

Скопируйте событие 7 и инвертируйте в нем условие, кликнув правой кнопкой мыши и далее по команде Invert condition (Инвертировать состояние), а в действии для кнопки button вместо кадра анимации 2, впишите 1.

Таким образом, вы создали событие, которое возвращает состояние кнопки (кнопка отжата), если ее имя не соответствует выделенной копии, и не прописана в глобальном значении state. Если вы все сделали правильно, то у вас должно получиться 2 новых события (7 и 8) как на рисунке 26.

Рис. 26

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

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

Итак, для события 7 мы создаем новое под-событие. Снова выбираем спрайт button и сравниваем приватное значение select, вписав в поле Value значение "button1".

Не создавая для этого под-события никакого действия, создаем еще одно под-событие. Выбираем объект System, далее команду Compare и вписываем в поле Value 1 выражение blade[Rotate].Speed. В Comparision выбираем Great that (Больше) и ниже в поле Value 2 вписываем значение 0.

Напротив этого под-события создаем действие. Выбираем спрайт blade, далее вкладка Rotate, затем находим и кликаем по команде Set rotation speed (задать скорость вращения) и вписываем выражение blade[Rotate].Speed-4.

Объясню, что мы сейчас сделали: первая копия кнопки button должна выключать вентилятор полностью (останавливать его), поэтому мы создали 2 под-события (8 и 9), которые при клике ЛКМ на первую кнопку button1 сравнивают скорость вращения лопастей вентилятора, и если эта скорость больше чем 0, то выражение blade[Rotate].Speed-4 каждый тик вычитает скорость из текущей до полной остановки.

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

Рис. 27

Далее скопируйте 8-ое событие (поставив его параллельно) и замените следующие значения:

В условии button: Value ‘select’ Equal to вместо button1 впишите button2. Далее ниже в под-событии, где blade[Rotate].Speed замените Great that (Больше) на Lower that (Меньше) и вместо 0 впишите значение 750.

В действии, где blade: Set rotation speed to замените выражение на blade[Rotate].Speed+4. Это у вас должно быть под-событие 11, далее скопируйте его еще раз постав также параллельно и вместо Lower that (Меньше) опять вписываем Great that (Больше), а значение 750 не меняем! Напротив, в действии вместо blade[Rotate].Speed+4 ставим blade[Rotate].Speed-4. Сравниваем результат с рисунком 28.

Рис. 28

Объясню, что мы сейчас сделали: когда игрок кликает по второй копии кнопки button, то исходя из под-событий 11 и 12, включается первая скорость вращения лопастей вентилятора. Например, под-событие 11 гласит так — если скорость лопастей меньше 750, то тогда каждый тик добавлять скорость +4, а под-событие 12 гласит, что если скорость больше 750, то каждый тик вычитать из нее -4.

Теперь нам нужно создать события для третьей копии кнопки button. Для этого еще раз скопируйте событие 8 (потому, что нам потребуется только одно под-событие) и в строке button: Value ‘select’ Equal to вместо button2 впишите button3. В под-событии (оно у вас должно быть под номером 14) меняем Great that (Больше) на Lower that (Меньше) и вместо 0 вписываем 2000. Напротив, в действии меняем выражение blade[Rotate].Speed-4 на blade[Rotate].Speed+4.

Таким образом, мы создали событие 13 и под-событие 14, которые гласят: когда игрок кликает по третьей копии объекта button, если скорость лопастей вентилятора меньше 2000, то каждый тик добавлять +4 к скорости. Если вы все сделали правильно, то события у вас должны получиться как на рисунке 29.

Рис. 29

Запустите игру и попробуйте пощелкать ЛКМ по кнопкам на вентиляторе. Вы увидите, что при нажатии одной из копии кнопок, она меняет свое состояние (нажата), при этом остальные кнопки должны возвращаться к первоначальному состоянию (отжата). Также вы должны увидеть, как начинают вращаться или постепенно останавливаются лопасти у вентилятора при нажатии на соответствующую копию спрайта button.

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

Так как у нас будет 2 способа вращения регулятора громкости, то в этой же группе создаем еще одну под-группу с именем keyboard и пишем комментарий (я написал «Способ 1 — вращение регулятора громкости с помощью клавиатуры»). См. рис. 30.

Рис. 30

Первый способ вращения очень простой и в нем будет всего 4 события. В группе keyboard создаем новое событие:

Выбираем объект Mouse & Keyboard и находим команду Key is down? (Зажать клавишу?), в открывающемся списке выбираем Up arrow (Стрелка вверх).

Далее создаем под-событие. Выбираем спрайт volumecontrol, далее команду Compare angle. В Comparison выбираем Less that (Меньше), а в Angle (Угол) вписываем значение 250.

Теперь напротив создаем действие: выбираем volumecontrol, находим команду Set angle (Задать угол) и вписываем выражение volumecontrol.Angle+1.

Итак, мы создали событие и под-событие, которые гласят: когда игрок нажимает и удерживает клавишу вверх и если угол регулятора громкости меньше 250, то каждый тик поворачивать регулятор вперед (+1 к его текущему углу).

Теперь копируем событие 16 вместе с под-событием и в условии меняем Up arrow (Стрелка вверх) на Down arrow (Стрелка вниз), далее Less that (Меньше) на Greater that (Больше) и последнее, меняем выражение volumecontrol.Angle+1 на volumecontrol.Angle-1.

Таким образом, мы создали события, которые гласят: когда игрок нажимает и удерживает клавишу вниз и если угол регулятора громкости больше 0, то каждый тик поворачивать регулятор назад (-1 к его текущему углу).

Если вы все сделали правильно, то у вас должно получится как на рисунке 31.

Рис. 31

Запустите игру и на клавиатуре попробуйте нажать и удерживать стрелки вверх или вниз. Регулятор должен вращаться до тех пор, пока не достигнет угла 250 или 0.

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

Для группы Radio создаем под-группу с именем mouse и ставим ее параллельно под-группе keyboard. В комментариях пишем что угодно (я написал «Способ 2 — вращение регулятора громкости с помощью мыши»). См. рис. 32.

Рис. 32

Перед тем как начать создавать события, давайте сразу создадим все необходимые глобальные значения, которых у нас должно быть не много не мало, а целых 4 штуки. Переходим на панель Project (Проект) и создаем 4 глобальных значения с именами: radio, oldAng, newAng и fullAng. У всех у них должен быть Type (Тип) цифровой Number, а значения 0, кроме fullAng, у которого вы должны вписать значение 250. См. рис. 33.

Рис. 33

Теперь переходим в под-группу mouse и создаем новое событие.

Выбираем объект Mouse & Keyboard, далее кликаем по команде On object clicked (Кликнуть по объекту один раз) и в открывшемся окне выбираем спрайт volumecontrol (оставив клавишу Left в поле Mouse button и Clicked в Clicked type). Далее, здесь же создаем смежное условие (новое условие в событии 20).

Выбираем объект Mouse & Keyboard, далее команду Mouse is over object? (Мышь перекрывает объект?) и в открывшемся окне выбираем спрайт volumecontrol.

Теперь создаем под-событие. Выбираем объект System, далее Trigger once while true. Напротив этого под-события создаем действие.

Выбираем объект System, далее с помощью команды Set value (Задать значение) для глобального значения oldAng вписываем выражение angle(MouseX, MouseY, volumecontrol.X, volumecontrol.Y).

Далее ниже создаем еще одно действие для этого же под события. Выбираем объект System, далее с помощью команды Set value (Задать значение) для глобального значения radio пишем значение 1.

Объясню, что мы сделали: когда игрок наводит курсор на регулятор громкости и нажимает ЛКМ (не отпуская), то он записывает значения угла между точками (MouseX, MouseY, volumecontrol.X, volumecontrol.Y) в глобальное значение oldAng и включает события управления (которые мы создадим позже), изменив глобальное значение radio с 0 на 1.

Примечание: выражение, с помощью которого вычисляется угол между точками, называется Angle between points (Угол между точками) и находится в выражениях, во вкладке math объекта System. Это на тот случай, если вдруг скопированное выражение из урока у вас не заработает, хотя у меня такого никогда не было, но было у тестера, который проверял урок перед публикацией.

Сравните свой результат с рисунком 34.

Рис. 34

Далее нам необходимо создать обратное событие, которое меняло бы глобальное значение radio обратно на 0, в случае если игрок отпустит ЛКМ или уберет курсор с регулятора громкости.

Итак, создаем новое событие. Выбираем объект Mouse & Keyboard, далее команду On key released и в списке выбираем Left mouse button. Далее здесь же создаем еще два смежных условия.

Выбираем объект System и кликаем по команде OR. Последнее смежное условие копируем из события 20, а именно Mouse is over volumecontrol и инвертируем его.

Напротив, в действии скопируйте и вставьте действие из под-события 21, а именно System: Set global variable ‘radio’ to 1 и замените 1 на 0. Если все сделали правильно, то должно получиться как на рисунке 35.

Рис. 35

Теперь мы создаем сам механизм вращения, а точнее то, что происходит, когда глобальное значение radio равняется 1. Будьте внимательны! Событие будет не простым, и будет иметь несколько под-событий и смежных условий.

Создайте новое событие. Выберите объект System, далее команду Compare global variable (Сравнить глобальное значение). В списке выбираем глобальное значение radio, а ниже в Compare to (Ровно) вписываем значение 1. Напротив, в действии, с помощью команды Set value, для глобального значения newAng вписываем выражение angle(MouseX, MouseY, volumecontrol.X, volumecontrol.Y).

Далее для события 23 создаем под-событие. Выбираем объект System и ищем команду Angle is clockwise of… (Угол по часовой стрелке…). В поле First angle (Первый угол) вписываем выражение global('newAng'). В поле Test у нас должно быть выбрано Clockwise (Направление по часовой стрелке), а ниже в поле Second angle (Второй угол) вписываем выражение global('oldAng').

Напротив, в действии для этого под-события, находим спрайт volumecontrol, далее выбираем команду Rotate clockwise (Повернуть по часовой стрелке) и вписываем выражение AngleDiff(global('oldAng'), global('newAng')).

Далее для под-события 24 создаем еще одно под событие. Выбираем спрайт volumecontrol и далее находим команду Compare angle (Сравнить угол). В Comparision (Сравнение) выбираем Less than (Меньше), а ниже в поле Angle вписываем значение 300. Напротив, в действии для этого же спрайта задаем угол, вписав выражение Clamp(volumecontrol.Angle, 0, 250) в команду Set angle (Задать угол).

Теперь для события 24 создайте параллельное событие, выбрав объект System и кликнув по команде Else (Еще). Учтите, что это событие должно состыковаться с событием 24 тонкой графической линией. См. рис. 36.

Рис. 36

Теперь для события Else (Еще) создаем действие. Выбираем спрайт volumecontrol и, найдя команду Rotate counter-clockwise (Повернуть против часовой стрелки) вписываем выражение AngleDiff(global('oldAng'), global('newAng')).

Теперь скопируйте под-событие 25 вместе с действием и вставьте его под событием Else (Еще). См. рис. 37.

Рис. 37

В скопированном под-событии, в условии volumecontrol: Angle Less that 300, замените Less that (Меньше) на Greater that (Больше). Напротив, в действии замените выражение Clamp(volumecontrol.Angle, 0, 250) на Clamp(volumecontrol.Angle, 0, 0).

Теперь нам осталось создать последнее заключительное событие для регулятора громкости радио.

Выбираем объект System и далее команду Always (Всегда). Напротив создаем действие. Находим глобальное значение oldAng и с помощью команды Set value (задать значение) вписываем выражение global('newAng').

Итак, что мы сделали. Когда глобальное значение radio становится равным 1, то в глобальное значение newAng записывается угол между двумя точками, и с этого момента спрайт volumecontrol будет вращаться в соответствии с постоянной разницей между углами самого спрайта и курсора. Само вращение происходит с помощью двух действий Rotate clockwise (Повернуть по часовой стрелке) и Rotate counter-clockwise (Повернуть против часовой стрелки), а ограничение на угол вращения задается в событиях 25 и 27.

В итоге ваше событие для регулятора громкости вместе с под-событиями должно выглядеть как на рисунке 38.

Рис. 38

Запустите игру и, наведя курсор на регулятор громкости радио, зажмите ЛКМ. Теперь перемещая курсор по регулятору, он будет поворачиваться в точности, как если бы вы поворачивали его рукой. Учтите, что если ваш курсор мыши соскочит с регулятора (выйдет за его пределы), то регулятор остановит вращение. Поэтому если вы хотите сделать так, что бы кликнув по регулятору и зажав ЛКМ, курсор можно было уводить за пределы спрайта, и при этом он все равно продолжал свое вращение до тех пор, пока вы не отпустите ЛКМ — то просто удалите 2 условия (OR и инвертированное условие Mouse is over volumecontrol) в событии 22.

Теперь приступаем к озвучиванию всех событий в игре. Для начала перейдите на панель Project, и в папку Files вашего проекта загрузите все имеющиеся звуки из папки sounds, которая находится в ранее распакованном вами архиве material. В итоге у вас должны быть загружены 6 файлов. См. рис. 39.

Рис. 39

Теперь создаем новую группу с именем Sounds, в комментариях пишем что угодно, я написал: «Звуки и музыка». Так как озвучивать нам предстоит почти все объекты в сцене, я предлагаю поделить события для них еще по нескольким поп-группам. Поэтому создаем под-группу с именем buttons, в которой будут все необходимые события для озвучивания кнопок.

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

Итак, перед нами стоит первая задача — это озвучить нажатие кнопок у вентилятора. Нам необходимо создать событие, в котором, при однократном нажатии ЛКМ на одной из копии кнопки button, один раз проигрывался звук «buttonfan.wav». При этом звук должен работать только тогда, когда кнопка находится в состоянии «Отжата», то есть если мы кликаем по уже нажатой кнопки button, то звука быть не должно. Попробуйте самостоятельно создать это событие, если у вас вдруг ничего не получится, вы можете воспользоваться подсказкой ниже.

Событие 30 для под-группы buttons.

EVENT:

[Событие] Условие: Mouse & Keyboard > On object clicked (Mouse button > Left, Click type > Clicked, Object > Button).
[+ Под-событие] Условие: button > Compare animation frame (Comparision > Equal to, Animation frame > 1).
[+ + Под-событие] Условие: System > Trigger once while true; Действие: XAudio2 > Autoplay resource (Resource to load > buttonfan.wav, Loop? > No loop).

Примечание: Знак "+" означает уровень вложенности под-события относительно основного события.

Сравните свой результат с рисунком 40.

Рис. 40

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

Теперь создаем под-группу light и располагаем ее параллельно под-группе buttons. В ней мы будем озвучивать события включения и отключения лампы. Вы спросите — а почему у включения света один звук, а у отключения другой? Все просто, дело в том, что все эти звуки я записывал в своей комнате и у моей лампы действительно при включении света один звук, а при отключении другой. Поэтому я подумал о том, что было бы неплохо объяснить читателям, как сделать два разных звука на одно и тоже действие.

Итак, ставим задачу: нам необходимо сделать так, чтобы при однократном нажатии клавиши Space включался свет и при этом раздавался один звук (lighton.wav), а при повторном нажатии на клавишу — свет выключался и при этом раздавался совсем другой звук (lightoff.wav).

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

Событие 32 для под-группы light.

EVENT:

[Событие] Условие: Mouse & Keyboard > On key pressed (Key > Space).
[+Под-событие] Условие: System > Compare global variable (Variable > light, Comparision > Equal to, Compare to > 0).
[+ + Под-событие] Условие: System > Trigger once while true; Действие: XAudio2 > Autoplay resource (Resource to load > lighton.wav, Loop? > No loop).
[+Под-событие] Условие: System > Compare global variable (Variable > light, Comparision > Equal to, Compare to > 1).
[+ + Под-событие] Условие: System > Trigger once while true; Действие: XAudio2 > Autoplay resource (Resource to load > lightoff.wav, Loop? > No loop).

Сравните свой результат с рисунком 41.

Рис. 41

Запустите игру и несколько раз понажимайте клавишу Space, каждый раз при включении и отключении света вы должны слышать разные звуки. Теперь создаем под-группу fan и располагаем ее параллельно под-группе light. В этой группе мы озвучим само вращение лопастей, но, хочу сразу предупредить, что событий будет несколько, и они будут не простыми. Дело в том, что у нас две скорости вращения лопастей и у каждой из них разное звучание. Я хочу показать вам, как можно используя всего 1 файл сделать из него 2 разных звука.

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

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

EVENT:

[Событие] Условие: System > Start of layout; Действие: XAudio2 > Load resource (Resource to load > fan.wav, Channel > 1, Loop? > Loop). Действие 2: XAudio2 > Play (Channel > 1). Действие 3: XAudio2 > Set frequency ratio (Channel > 1, Frequency ratio > 0).

Объясню, что мы сделали: при запуске игры объект XAudio2 загружает на 1 канал звук «fan.wav» и с помощью команды loop начинает его проигрывать по кругу. Второе действие play channel включает сам звук, а вот третье действие задает изначальный коэффициент частоты и когда он равен 0, то звука нет (он как бы отключен, хотя существует и проигрывается).

Сравните получившееся у вас событие с рисунком 42.

Рис. 42

Двигаемся дальше. Создайте новое событие:

EVENT:

[Событие] Условие: button > Compare animation frame (Comparision > Equal to, Animation frame > 2).
[+Под-событие] Условие: button > Compare a private variable (Private variable > select, Comparision > Equal to, Value > "button1").
[++Под-событие] Условие: System > Compare (Value 1 > XAudio2.FreqRatio(1), Comparision > Greater than, Value 2 > 0); Действие: XAudio2 > Set frequency ratio (Channel > 1, Frequency ratio > XAudio2.FreqRatio(1)-0.003).
[+Под-событие] Условие: button > Compare a private variable (Private variable > select, Comparision > Equal to, Value > "button2").
[++Под-событие] Условие: System > Compare (Value 1 > XAudio2.FreqRatio(1), Comparision > Lower than, Value 2 > 0.5); Действие: XAudio2 > Set frequency ratio (Channel > 1, Frequency ratio > XAudio2.FreqRatio(1)+0.003).
[++Под-событие] Условие: System > Compare (Value 1 > XAudio2.FreqRatio(1), Comparision > Greater than, Value 2 > 0.5); Действие: XAudio2 > Set frequency ratio (Channel > 1, Frequency ratio > XAudio2.FreqRatio(1)-0.003).
[+Под-событие] Условие: button > Compare a private variable (Private variable > select, Comparision > Equal to, Value > "button3").
[++Под-событие] Условие: System > Compare (Value 1 > XAudio2.FreqRatio(1), Comparision > Lower than, Value 2 > 1.0); Действие: XAudio2 > Set frequency ratio (Channel > 1, Frequency ratio > XAudio2.FreqRatio(1)+0.003).

Объясню, что мы сейчас сделали: когда пользователь кликает на кнопку вентилятора (любую из трех копий), то эта кнопка меняет свой кадр 1 (отжата) на кадр 2 (нажата), и в этот момент, если приватное значение button равно 1 и если коэффициент частоты звука больше 0, то в действии каждый тик вычитается -0.003 коэффициент частоты до 0, то есть пока звук полностью не исчезнет.

Далее, если приватное значение button равно 2 и если коэффициент частоты звука меньше 0.5 (это среднее звучание), то в действии каждый тик прибавляется +0.003 коэффициент частоты до 0.5, то есть до среднего звучания. А если коэффициент частоты звука больше 0.5, то в действии каждый тик вычитается -0.003 коэффициент частоты до 0.5.

Если приватное значение button равно 3 и если коэффициент частоты звука меньше 1.0 (это нормальное состояние звука), то в действии каждый тик прибавляется +0.003 коэффициент частоты до 1.0, то есть до тех пор, пока он не начнет играть в полную силу и с нормальной скоростью. Надеюсь, это понятно.

Сравните получившееся у вас событие с рисунком 43.

Рис. 43

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

Теперь создайте под-группу под названием music и поставьте ее параллельно под-группе fan. Как вы уже догадались, в ней мы будем озвучивать само радио, а точнее то, что оно будет ловить. Казалось бы, что нам стоит озвучить радио? Загрузил музыку в XAudio2 и пусть себе играет, но, к сожалению, не все так просто. Давайте по порядку.

Для начала в новой созданной нами группе music создаем событие:

[Событие] Условие: System > Start of layout; Действие: XAudio2 > Play music from resource (Resource > music.wav). Действие 2: XAudio2 > Set music looping (Loop music > Loop).

В этом событии, при старте игры в первом действии, с помощью объекта XAudio2 мы включаем музыку. А во втором действии, с помощью Loop, мы делаем так, чтобы она все время играла по кругу.

Сравните получившееся событие с рисунком 44.

Рис. 44

Теперь давайте поговорим о проблеме. Все дело в том, что в Construct у объекта XAudio2 существует команда Set volume, которая задает громкость музыки в диапазоне значений от 0 до 100, но, к сожалению, эта команда работает неправильно и регулирование громкости происходит не равномерно, а по дуге. То есть, когда вы ставите значение громкости 50, то музыки не слышно, а чтобы она заиграла хотя бы наполовину, приходится ставить значение громкости 90. Для более наглядной демонстрации посмотрите рисунок 45 схему «А».

Рис. 45

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

Итак, перед созданием следующего события создайте новое глобальное значение с именем convert. Тип значения должен быть number, а само значение 0. Для чего оно нужно, я объясню позже, а пока приступаем к созданию нового события:

EVENT:

[Событие] Условие: System > Always; Действие: System > Set value (Variable > convert), а в поле Variable вписываем сложное выражение round((global('fullAng')-volumecontrol.Angle)^2/1250). Действие 2: XAudio2 > Set volume, а в поле Volume вписываем второе сложное выражение 50-global('convert')+50.

Итак, пришло время объяснить, что же мы сейчас сделали. Само условие Always (Всегда), я думаю, объяснять не стоит, а вот действия заслуживают особого внимания.

Если вы читали статью «Выражения в Construct», то наверняка помните, что выражение round, служит для округления чисел, поэтому в первом действии для глобального значения convert мы вписываем значение полного угла fullAng (если помните, оно равняется 250) и затем из него вычитаем угол спрайта volumecontrol. Далее получившееся число мы возводим во вторую степень, для того, чтобы число возросло в прогрессии, а затем уже делим его на 1250 и тут нам на помощь приходит выражение round, которое округляет получившееся при делении дробное число. В результате, на выходе мы получаем целое число в диапазоне от 50 до 0, которое записывается в глобальное значение convert. Теперь это уменьшающееся число необходимо было обратить, чтобы оно с помощью своей прогрессии равномерно увеличивало громкость радио. Тогда мы создали второе действие, где заранее вычитали из 50 глобальное значение convert, а затем к получившемуся числу уже добавляли 50. Таким образом, мы добились абсолютно равномерного нарастания и уменьшения звука, как на рисунке 45, схеме «Б».

Сравните получившееся у вас событие с рисунком 46.

Рис. 46

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

Теперь создайте последнюю под-группу с именем noise и точно так же, как и предыдущие группы, поставьте ее параллельно группе music.

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

Итак, в под-группе noise создаем новое событие:

EVENT:

[Событие] Условие: System > Start of layout; Действие: XAudio2 > Load resource (Resource to load > noise.wav, Channel > 2, Loop? > Loop). Действие 2: XAudio2 > Play (Channel > 2).

Так как у нас канал 1 занят музыкой, мы загрузили noise.wav на канал 2 и сразу включили звук по кругу. Сравните событие с рисунком 47.

Рис. 47

Далее в этой же под-группе создаем новое событие:

EVENT:

[Событие] Условие: System > Compare global variable (Variable > radio, Comparison > Equal to, Compare to > 0).
Смежное условие: System > OR.
Смежное условие (инвертировано): Mouse & Keyboard > Key is down? (Key > Up arrow).
Смежное условие (инвертировано): Mouse & Keyboard > Key is down? (Key > Down arrow); Действие: XAudio2 > Set muted (Channel > 2, Muted? > Muted).

В этом событии мы задали условия, что когда глобальное значение radio равно 0 или когда игрок не нажимает клавишу вверх или вниз (т.е. не пытается управлять регулятором громкости с помощью клавиш), то звук шума noise.wav — мутируется (отключается).

Сравните результат с рисунком 48.

Рис. 48

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

EVENT:

[Событие] Условие: System > Compare global variable (Variable > radio, Comparison > Equal to, Compare to > 1); Действие: XAudio2 > Set muted (Channel > 2, Muted? > Unmuted).

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

EVENT:

[Событие] Условие: Mouse & Keyboard > Key is down (Key > Up arrow).
Смежное условие: System > OR
Смежное условие: Mouse & Keyboard > Key is down (Key > Down arrow); Действие: XAudio2 > Set muted (Channel > 2, Muted? > Unmuted).

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

Сравните получившееся событие с рисунком 49.

Рис. 49

Итак, пришло время создать последнее событие для этой под-группы и в этом уроке:

EVENT:

[Событие] Условие: System > Always; Действие: XAudio2 > Set volume (Channel > 2), а в поле Volume вписываем непростое выражение round(50-global('convert')/2)-65.

Объясню, что мы сделали. Дело в том, что лимит и диапазон громкости звука для каналов отличается от стандартной громкости для музыки, поэтому в действии для события Always мы создали выражение, которое создает отрицательное значение для понижения звука шума, так как в каналах значение 0 — это нормальная громкость. Соответственно, чтобы сделать шум тише приходится уменьшать значение, делая его отрицательным, например, -50. Сравните свой результат с рисунком 50.

Рис. 50

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

На этом урок про Тумблеры закончен.

Подведение итогов

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

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

Исходник этого урока вы можете скачать здесь: Исходник «Тумблеры».
Пример из этого урока вы можете скачать здесь: Пример «Тумблеры».

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

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



Автор урока: Edison

Опубликовано: 26 июня, 2011

Категория: Уроки по Construct

Комментарии:

  1. Zaharik:

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

  2. Slavak:

    Урок отличный я за час выполнил только У меня лопости поверх решотки а должно быть наобород 😀

  3. TReSHeRRR:

    Урок СУПЕРРРРРРРРРРРРР *BRAVO* *BRAVO* *BRAVO* *THUMBS UP* *THUMBS UP* *THUMBS UP* !!! скроее бы уже вышел TDS за 5 минут *UNKNOWN* *UNKNOWN*

  4. Darkerion:

    Да "TDS за 5 минут"!!! Скорей!!! *CRAZY* А уроки супер!!! =)