Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

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

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

К концу этого урока у нас будет завершенная система, в которой кнопки могут активироваться Игроком и правильно взаимодействовать с ранее созданной платформой.

1. Создание кнопки

Чтобы начать создание кнопки, сначала создайте новый Entity Template.

Затем переименуйте Entity в соответствии с его назначением, настройте Mesh, который будет использоваться в качестве его визуального представления, и добавьте необходимые физические компоненты, чтобы она могла правильно взаимодействовать в игре.

После этого создайте новый Logic Brick и свяжите его с кнопкой Entity.

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

В конце этого шага у нас будет готова базовая структура кнопки для получения логики активации.

image.png

Теперь очень важный шаг: мы не можем забыть добавить тег button к кнопке Entity.

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

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

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

Так что перед тем, как продолжить, убедитесь, что вы создали тег button и добавили его к кнопке Entity.

image.png

Теперь давайте также добавим свойство к кнопке Entity.

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

Создайте новое свойство под названием Active Time, типа Float.

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

Это делает систему более гибкой, потому что каждая кнопка может иметь разное время активации. Например, одна кнопка может оставаться активной в течение 3 секунд, в то время как другая кнопка может оставаться активной в течение 10 секунд, не меняя сам Logic Brick.

image.png

2. Создание логики кнопки

Теперь, когда наша Entity готова, с настроенным тегом и свойством, давайте начнем создавать поведение кнопки.

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

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

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

Для этого создайте новое свойство в Logic Brick кнопки под названием Active Button, типа Boolean.

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

image.png

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

В On Update мы будем постоянно проверять, активна кнопка или неактивна, используя свойство Active Button, которое мы только что создали.

Для этого получите его значение, используя Get Active Button, и используйте узел If для проверки его состояния.

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

Для этого добавьте узел Collided With.

Этот узел требует Rigid Body Component, поэтому получите кнопку Entity и, от нее, получите Rigid Body Component, который мы добавили при настройке физики.

Нам также нужно сказать узлу, какой объект мы хотим обнаруживать. Для этого добавьте тег player к персонажу и передайте этот тег в Collided With.

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

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

image.png

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

После этого мы создадим поведение, ответственное за ее активацию.

Для этого следуйте условию True узла If, который проверяет, активна кнопка или нет.

В этой последовательности мы будем использовать свойство Active Time, которое мы создали в кнопке Entity, для контроля того, как долго кнопка должна оставаться активной.

Сначала получите кнопку Entity и получите доступ к ее свойствам через узел Get Properties.

Затем используйте Get Property, соединяя ранее возвращенный словарь и используя Active Time в качестве Key.

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

image.png

Теперь выход Get Property возвращает значение свойства Active Time, которое определяет, как долго кнопка должна оставаться активной.

Далее добавьте узел Delay и используйте это значение как длительность.

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

После завершения Delay используйте Set Active Button и установите его значение на False.

С этим кнопка автоматически возвращается в неактивное состояние после времени, указанного в ее свойстве.

image.png

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

Выход узла Collided With возвращает значение Bool.

Когда это значение True, это означает, что кнопка столкнулась с Игроком.

В этот момент мы можем просто использовать Set Active Button и установить его значение на True.

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

С этим мы создали полный цикл поведения:

  • когда Игрок сталкивается с кнопкой, она активируется
  • после времени, определенного в Active Time, она деактивируется
  • после этого ее можно активировать снова путем другого столкновения

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

image.png

Все работает, но одна важная деталь по-прежнему отсутствует.

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

Именно здесь становится важным свойство Button Count, которое мы создали ранее в Scene.

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

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

Что нам нужно сделать сейчас, так это позволить кнопкам напрямую изменять свойство Button Count сцены всякий раз, когда они активируются и деактивируются.

Это отличная возможность попрактиковать еще одну очень важную функцию Logic Bricks в Cave: создание функций.

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

Поскольку свойство Button Count хранится в сцене, сначала нам нужно к нему получить доступ.

Для этого получите сцену, используя Get Scene, а затем используйте Get Properties.

image.png

3. Создание функции, которая управляет свойствами сцены

Из этих узлов мы создадим функцию.

Для этого выберите задействованные узлы, щелкните правой кнопкой мыши и выберите Promote Selection to Function.

image.png

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

В этом случае мы используем имя Set Scene Property.

image.png

Теперь давайте структурируем, как будет работать функция Set Scene Property.

Сначала передайте словарь свойств Scene узлу Get Property. Этот словарь приходит из потока Get Scene → Get Properties.

Затем измените выходной сигнал Get Property на Int, убедившись, что мы работаем с целыми значениями.

В Function Inputs создайте два новых параметра для этой функции:

  • Prop Name, типа String
  • Value, типа Int

Параметр Prop Name будет использоваться как Key в Get Property, что позволит функции получить доступ к нужному свойству внутри словаря свойств Сцены.

Затем мы обновим это свойство с помощью Set Property.

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

Мы снова передаем словарь свойств Сцены и используем Prop Name в качестве ключа.

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

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

image.png

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

Теперь вместо того, чтобы повторять всю логику, мы просто вызываем функцию сразу после установки Active Button в True.

Это означает, что в момент активации кнопки мы немедленно сообщаем логике платформы, что была нажата еще одна кнопка.

Для этого передаем имя свойства Button Count, которое хранится в Сцене, и отправляем значение 1 как инкремент.

Функция автоматически добавит +1 к текущему значению этого свойства.

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

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

image.png

Чтобы показать, насколько это просто и гибко, давайте вернемся к логике активной кнопки.

Сразу после завершения времени активации и установки Active Button в False мы снова вызовем Set Scene Property.

Параметр Prop Name будет Button Count, используя то же свойство Сцены.

Но на этот раз параметр Value будет -1.

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

image.png

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

image.png

Теперь наша логика работает так, как и ожидалось.

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

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

Перед установкой Active Button в True добавьте Sequence.

Поскольку нам больше не нужно три потока, мы можем удалить один из выходов, кликнув правой кнопкой мыши и выбрав Remove Last Flow Output, оставив только два пути.

Затем получите дочернюю сущность кнопки, называемую ButtonMesh, получите доступ к ее Mesh Component и отрегулируйте значение Tint.

На оси Y установите значение 25, чтобы кнопка выглядела зеленой, когда она активирована.

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

image.png

Аналогичным образом мы восстановим оригинальный цвет кнопки, когда она станет неактивной.

Используйте ту же логику, но в потоке, где мы устанавливаем Active Button в False.

В этот момент снова получите дочернюю сущность ButtonMesh, получите доступ к ее Mesh Component и отрегулируйте значение Tint.

Чтобы вернуть исходный цвет, просто установите все значения Tint обратно на 1, восстанавливая первоначальное визуальное состояние кнопки.

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

image.png

Выбирая экземпляр button template, который мы добавили в сцену, мы можем получить доступ к его свойствам и изменить значение Active Time.

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

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

image.png

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

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

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

Помимо логики, мы добавили важную визуальную обратную связь для игрока.

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

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

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

image.png