Оглавление:

Сетевое соперничество: игра с малой задержкой для BBC Micro: бит: 10 шагов (с изображениями)
Сетевое соперничество: игра с малой задержкой для BBC Micro: бит: 10 шагов (с изображениями)

Видео: Сетевое соперничество: игра с малой задержкой для BBC Micro: бит: 10 шагов (с изображениями)

Видео: Сетевое соперничество: игра с малой задержкой для BBC Micro: бит: 10 шагов (с изображениями)
Видео: ТОП 3 ЛУЧШИХ СЕРВИСА ДЛЯ ОБЛАЧНОГО ГЕЙМИНГА | 2023 | СНГ 2024, Июль
Anonim
Сетевое соперничество: игра с малой задержкой для BBC Micro: bit
Сетевое соперничество: игра с малой задержкой для BBC Micro: bit
Сетевое соперничество: игра с малой задержкой для BBC Micro: bit
Сетевое соперничество: игра с малой задержкой для BBC Micro: bit

В этом уроке я объясню, как реализовать базовую многопользовательскую игру на BBC micro: bit со следующими функциями:

  • Простой интерфейс
  • Низкая задержка между нажатиями кнопок и обновлением экрана
  • Гибкое количество участников
  • Легкое управление игрой с помощью главного удаленного («корневого») устройства.

Игра по сути является симулятором политики. Все игроки начинают игру без принадлежности к какой-либо команде, за исключением двух игроков. Один из этих игроков прикреплен к команде A, а другой - к команде B.

Цель игры для каждого игрока - быть в команде с большинством игроков в то время, когда все конвертируются.

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

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

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

На диаграмме выше указаны следующие состояния:

  • Не назначен
  • Слушайте A
  • Слушайте B
  • Команда А
  • Команда B

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

На протяжении всего руководства я предполагаю, что вы используете редактор Microsoft MakeCode, который можно найти по адресу:

Полную реализацию игры можно найти здесь:

makecode.microbit.org/_CvRMtheLbRR3 («microbit-demo-user» - это название проекта)

А реализацию главного («корневого») сетевого контроллера можно найти здесь:

makecode.microbit.org/_1kKE6TRc9TgE («microbit-demo-root» - это название проекта)

Я буду ссылаться на эти примеры в своем руководстве.

Шаг 1. Соображения по поводу дизайна общей картины

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

  1. Мы хотим контролировать действия устройства в зависимости от его текущего состояния.
  2. Мы хотим, чтобы устройство реагировало на ввод пользователя
  3. Мы можем захотеть отображать анимацию и графику, используя светодиодный дисплей 5 x 5.
  4. Мы хотим инициализировать значения данных в памяти устройства при загрузке устройства.
  5. Мы хотим передавать данные по беспроводной сети, используя радио устройства.
  6. Мы хотим прослушивать и получать данные по радио устройства и соответствующим образом их обрабатывать.

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

1. Мы хотим контролировать действия устройства в зависимости от его текущего состояния

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

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

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

3. Мы хотим отображать анимацию и графику на светодиодном дисплее 5 x 5

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

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

Прежде чем наше устройство что-либо сделает, приложение должно загрузить свои данные в память. Сюда входят постоянные переменные, названные для удобочитаемости кода, переменные, содержащие изображения, которые могут быть частью анимации, и переменные счетчика, которые должны начинаться с 0 для правильной работы. В итоге мы получим длинный список имен переменных и их вновь присвоенных значений. В качестве личного выбора стиля я буду обозначать постоянные значения, то есть значения, которые мне никогда не нужно будет изменять, используя ALL_CAPS. Я также добавлю к идентификаторам основных переменных префикс с именем категории, которое относится к типу объекта или типа, к которому относится этот идентификатор. Это попытка облегчить понимание кода. Я никогда не буду использовать такие имена переменных, как «item» или «x» из-за неоднозначности, возникающей при попытке расшифровать код.

5. Мы хотим передавать данные по беспроводной сети, используя радио устройства

На самом деле это довольно простая задача при использовании языка блоков MakeCode. Мы просто устанавливаем для всех устройств одну и ту же радиогруппу во время загрузки, а затем, когда мы хотим отправить сигнал, мы можем передать один номер в предоставленный нам блок «Radio send number». Важно, чтобы отправитель и получатель работали в одной радиогруппе, потому что в противном случае они будут отправлять или получать на разных частотах, и связь будет неудачной.

6. Мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их

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

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

  1. Мы хотим иметь возможность выбирать сигнал
  2. Мы хотим иметь возможность передавать сигнал

-

1. Мы хотим иметь возможность выбирать сигнал

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

2. Мы хотим иметь возможность передавать сигнал

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

В следующем разделе я подробнее расскажу о простом сигнальном протоколе.

Шаг 2: Сигнальный протокол: простой язык для сетевой коммуникации

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

0. Сброс

  • Идентификатор в коде: SIG-R
  • Целочисленное значение: 0
  • Цель: сообщить всем устройствам в пределах досягаемости, чтобы они перестали делать то, что они делают, и действовать так, как если бы они только что загрузились. Если этот сигнал достигнет каждого устройства в сети, вся сеть будет сброшена, и пользователи смогут начать новую игру. Этот сигнал может транслироваться только корневым устройством.

1. Преобразование A

  • Идентификатор в коде: SIG-A
  • Целочисленное значение: 1
  • Цель: сообщить любому устройству, которое находится в состоянии LISTEN_A, как только они получат сигнал преобразования, переключиться в состояние TEAM_A.

2. Преобразование B

  1. Идентификатор в коде: SIG-B
  2. Целочисленное значение: 2
  3. Цель: сообщить любому устройству, которое находится в состоянии LISTEN_B, как только они получат сигнал преобразования, переключиться в состояние TEAM_B.

Шаг 3. Мы хотим контролировать действия устройства в зависимости от его текущего состояния

Мы хотим контролировать действия устройства в зависимости от его текущего состояния
Мы хотим контролировать действия устройства в зависимости от его текущего состояния
Мы хотим контролировать действия устройства в зависимости от его текущего состояния
Мы хотим контролировать действия устройства в зависимости от его текущего состояния
Мы хотим контролировать действия устройства в зависимости от его текущего состояния
Мы хотим контролировать действия устройства в зависимости от его текущего состояния

Наконец-то мы можем приступить к написанию кода.

Сначала откройте новый проект в Make Code.

  • Создайте новую функцию. Я назвал свой цикл, потому что это основной цикл приложения
  • Добавьте блок цикла, который будет повторяться бесконечно. Я использовал while (true), потому что буквальное значение true никогда не будет ложным, следовательно, поток управления приложения никогда не выйдет из цикла
  • Добавьте достаточное количество блоков if-else, чтобы проверить, находится ли устройство в любом из пяти возможных состояний.
  • Создайте переменную для хранения текущего состояния устройства
  • Создайте переменные для представления каждого из пяти возможных состояний

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

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

Примечание: не беспокойтесь о серых блоках на третьем изображении. Я вернусь к ним позже.

Шаг 4. Мы хотим реагировать на вводимые пользователем данные

Мы хотим реагировать на ввод пользователя
Мы хотим реагировать на ввод пользователя
Мы хотим реагировать на ввод пользователя
Мы хотим реагировать на ввод пользователя

Теперь мы хотим рассказать устройству, как обрабатывать нажатия кнопок. Сначала можно было бы просто использовать блоки «Когда кнопка нажата» в категории ввода, но нам бы хотелось более детального контроля, чем это. Мы будем использовать блок «on event from (X) with value (Y)» из категории управления в расширенном разделе, потому что мы продвинулись в этом руководстве.

  • Создайте четыре блока «по событию из…».

    • Два из них должны проверять источник события «MICROBIT_ID_BUTTON_A».
    • Два из них должны проверять источник события «MICROBIT_ID_BUTTON_B».
    • Из двух событий, нацеленных на каждую кнопку:

      • Следует проверить наличие события типа «MICROBIT_BUTTON_EVT_UP»
      • Следует проверить наличие события типа «MICROBIT_BUTTON_EVT_DOWN»
    • Примечание. Эти параметры, написанные заглавными буквами, являются метками, которые используются в низкоуровневом коде micro: bit. Это просто заполнители, которые позже заменяются целыми числами, когда код компилируется в исполняемый двоичный файл. Людям легче использовать эти метки, чем искать, какое целое число нужно ввести, хотя оба будут работать одинаково.
  • Я выбрал стиль, чтобы каждый блок «on event from…» вызывал функцию, описывающую вызванное событие. Хотя это и не является строго необходимым, на мой взгляд, это улучшает читаемость. При желании они могут поместить код обработки событий внутри самого блока «on event from…».

    Примечание. Блок кода, который обрабатывает реакцию устройства на событие, интуитивно называется «обработчиком событий»

  • Добавьте в каждый обработчик событий ту же структуру if-else, которая используется для разделения потока управления на основе состояния устройства, что и структура в основном цикле состояния.
  • Добавьте блоки назначения, которые изменяют это состояние устройства в соответствии с нашей диаграммой состояний.

    • Мы знаем, что когда устройство находится в состоянии UNASSIGNED, устройство должно реагировать на нажатие кнопки A переходом в состояние LISTEN_A, а на нажатие кнопки B переходом в состояние LISTEN_B
    • Мы также знаем, что когда устройство находится в состоянии LISTEN_A или LISTEN_B, устройство должно реагировать на отпускание кнопки A и отпускания кнопки B, соответственно, переходом обратно в состояние UNASSIGNED.
    • Наконец, мы знаем, что, когда устройство находится в состоянии TEAM_A или TEAM_B, устройство должно реагировать на нажатие кнопки A и кнопки B, передавая SIG_A и передавая SIG_B соответственно.

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

Шаг 5: мы хотим инициализировать значения данных в памяти устройства при загрузке устройства

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

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

Вот значения, которые мы должны инициализировать:

  • Константы сигнала согласно сигнальному протоколу. Значения ДОЛЖНЫ быть:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Примечание. Я добавил к этим константам префикс «EnumSignals», чтобы обозначить, что эти переменные должны вести себя так, как если бы они были частью перечислимого типа, называемого сигналами. Вот как эти переменные могут быть реализованы в других языках программирования. Определение и объяснение перечислимых типов выходит за рамки моего руководства. Его можно погуглить, если они того пожелают. Эти префиксы являются просто стилистическим выбором и совсем не важны для правильного функционирования программы.
  • Константы состояния, которые могут быть произвольными, если они имеют значение. Я выбрал стиль, чтобы просто использовать целые числа по возрастанию от 0, например:

    • НЕ НАЗНАЧЕН = 0
    • LISTEN_A = 1
    • LISTEN_B = 2
    • TEAM_A = 3
    • TEAM_B = 4
    • Примечание: я принял такое же стилевое решение в отношении префиксов для этих переменных. Кроме того, я отмечу, что все, что касается этих назначений, значений и порядка, совершенно произвольно. Даже не имеет значения, что эти значения согласованы от устройства к устройству, потому что они используются только внутри, а не для связи по сети. Все, что имеет значение, - это то, что переменные имеют значение и что их можно сравнивать друг с другом, чтобы увидеть, эквивалентны они или нет.
  • Для удобства чтения константа называется BOOT_STATE и устанавливается в UNASSIGNED. Это делает тот факт, что мы сбрасываем в состояние загрузки, а не в более произвольное состояние, более явным, когда устройство получает сигнал сброса, который мы реализуем позже.
  • Константы анимации, используемые на следующем шаге для создания анимаций, которые позволяют прерывание с очень малой задержкой посредством пользовательского ввода. Мы пока не использовали их, но они обязательно будут объяснены и использованы в следующем разделе. Значение некоторых из них должно быть интуитивно понятным благодаря их названиям.

    • TICKS_PER_FRAME_LOADING_ANIMATION = 50
    • MS_PER_DEVICE_TICK = 10
    • MS_PER_FRAME_BROADCAST_ANIMATION = 500
    • MICROSECONDS_PER_MILLISECOND = 1000
    • NUMBER_OF_FRAMES_IN_LOADING_ANIMATION = 4
  • Еще одна переменная для анимации, на этот раз счетчик, который определенно непостоянен. Как и большинство счетчиков, мы инициализируем его значением 0

    iTickLoadingAnimation = 0

  • Создайте две серии переменных для хранения кадров анимации. Первая, которую я называю «анимация загрузки», должна иметь четыре изображения (о которых вы могли догадаться по последней постоянной инициализации), а вторая, которую я называю «анимация трансляции», должна иметь три изображения. Я рекомендую называть переменные, чтобы они соответствовали кадрам анимации, например ringAnimation0, ringAnimation1…

    Создайте те же значения изображения, что и я, или создайте более оригинальные и крутые изображения

  • И последнее, но не менее важное: мы должны установить для радиогруппы устройства значение 0 с помощью блока «Radio set group (X)».
  • При желании напишите сообщение «Инициализация завершена» для последовательного вывода, чтобы сообщить пользователю, что все прошло гладко.
  • Теперь, когда мы закончили настройку устройства, мы можем вызвать нашу функцию цикла состояний.

Шаг 6. Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5

Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5
Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5
Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5
Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5
Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5
Мы хотим отображать анимацию и графику с помощью светодиодного дисплея 5 X 5

А сейчас нечто соверешнно другое.

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

  • Создайте функцию для каждого изображения. Это позволит использовать один блок для отображения изображения вместо того, чтобы каждый раз редактировать javascript. В этой конкретной программе изображение не используется более одного раза, но я все же думаю, что этот стиль облегчает чтение кода.
  • Добавьте в каждую новую функцию блок «показать изображение (X) со смещением 0» с заменой имени соответствующей переменной изображения (X)
  • Добавьте в основной цикл состояния. Блоки «Показать строку (X)» для каждого блока, кроме того, который обрабатывает состояние UNASSIGNED. Добавьте символ для отображения устройства, чтобы указать его различные состояния. Вот что я сделал:

    • LISTEN_A: 'a'
    • LISTEN_B: 'b'
    • КОМАНДА_А: 'А'
    • TEAM_B: 'B'

      Для состояния UNASSIGNED вызовите функцию, которая обновит анимацию загрузки. Мы заполним детали этой функции ниже

  • Переключитесь в режим javascript.
  • Найдите каждый вызов X.showImage (0) и basic.showString (X)
  • Измените каждый на X.showImage (0, 0) или basic.showString (X, 0)

    • Добавление этого дополнительного аргумента установит задержку после действия равной 0. По умолчанию это не учитывается, и устройство приостанавливает работу на 400 мс после выполнения каждого из этих блоков.
    • Теперь у нас есть механизм почти без задержек для отображения наших изображений в наших блоках анимации, который мы теперь можем построить.

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

  • Создайте функцию, которая будет отображать широковещательную анимацию.
  • Внутри этого блока добавьте три вызова функций, по одному для каждого кадра анимации, в том порядке, в котором они должны отображаться.
  • Добавляйте блок «wait (us) (X)» после каждого вызова функции отображения изображений.

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

  • Замените (X) на (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • Теперь анимация должна работать правильно

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

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

    Если условие истинно, сбросьте iTickLoadingAnimation на 0

  • Добавьте блок условий if-else. Они определят, какой кадр анимации отображать.

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

  • Внизу блока увеличьте iTickLoadingAnimation
  • Теперь анимация должна работать правильно

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

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

Мы хотим передавать данные по беспроводной сети, используя радио устройства
Мы хотим передавать данные по беспроводной сети, используя радио устройства

Этот шаг намного короче предыдущего. Фактически, это, вероятно, самый короткий шаг во всем уроке.

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

  • На кнопке A нажата:

    • Если устройство находится в состоянии TEAM_A:

      Широковещательный сигнал SIG_A

  • На кнопке B нажата:

    • Если устройство находится в состоянии TEAM_B

      Широковещательный сигнал SIG_B

Создайте эти функции, если они еще не существуют.

В каждой функции:

  • Вызовите функцию анимации трансляции. Это заблокирует что-либо еще, пока оно не завершится, что будет в MS_PER_FRAME_BROADCAST_ANIMATION * 3 = 1,5 секунды. Константа умножается на три, потому что в анимации три кадра. Это произвольно, и можно добавить больше, если эстетическое обновление будет достаточно большим. Вторая цель этой анимации - не дать пользователю спамить широковещательную функцию.
  • Добавьте блок "номер радиопередачи (X)", где - константа сигнала, указанная в имени функции.

Это все, что нужно для передачи по радио.

Шаг 8: мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их

Мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их
Мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их
Мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их
Мы хотим прослушивать и получать данные по радио устройства и соответственно обрабатывать их

Это последний шаг в создании основного приложения.

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

Первый:

  1. Создайте блок кода, начинающийся с блока «Принято по радио (X)».
  2. При желании можно присвоить полученное значение другой переменной с более описательным именем.
  3. Вызвать функцию, которая будет обрабатывать сигнал

Во-вторых, в функции обработки сигналов:

  1. Создайте блок операторов if-else, которые разветвляют поток управления на основе значения сигнала.
  2. Если сигнал был SIG_R

    Установите состояние устройства на BOOT_STATE (поэтому мы создали эту константу ранее)

  3. Если сигнал был SIG_A и если текущее состояние LISTEN_A

    Установите состояние устройства на TEAM_A

  4. Если сигнал был SIG_B и если текущее состояние LISTEN_B

    Установите состояние устройства на TEAM_B

Вот и все. Приложение готово.

Шаг 9: Корневое устройство: мы хотим иметь возможность выбирать сигнал

Корневое устройство: мы хотим иметь возможность выбирать сигнал
Корневое устройство: мы хотим иметь возможность выбирать сигнал

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

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

  • Мы хотим позволить пользователю выбрать один из наших сигналов.
  • Мы хотим разрешить пользователю транслировать сигнал

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

Чтобы позволить пользователю выбрать сигнал:

  1. Инициализируйте 5 переменных в блоке "при запуске":

    1. Три сигнала (0, 1, 2)
    2. Количество сигналов (3)
    3. Переменная для хранения текущего выбранного сигнала (изначально установлен на первый сигнал, 0)
  2. Обработка нажатия кнопки A:

    1. Увеличить выбранный сигнал
    2. Убедитесь, что выбранный сигнал больше или равен количеству сигналов

      Если это так, установите для выбранного сигнала значение 0

  3. После блока при запуске запустите цикл "навсегда", который отображает текущее выбранное значение сигнала без задержки.

Чтобы позволить пользователю транслировать сигнал

  1. Установите радиогруппу на 0 в блоке "при запуске"
  2. Обработка нажатия кнопки B:

    Транслировать выбранный сигнал с помощью блока "номер радиопередачи (X)"

Вот и все. Приложение корневого узла чрезвычайно просто.

Шаг 10: Мы закончили

Мы закончили
Мы закончили

Выше изображены устройства, на которых запущено приложение. Двое справа запускают основное «пользовательское» приложение, а тот, что слева, запускает «корневое» приложение.

Я продемонстрировал эту игру на CS Connections 2018, недельной летней конференции для учителей средних и старших классов, посвященной образованию в области информатики. Я раздал учителям около 40 устройств и объяснил правила. Большинству эта игра показалась интересной, и многих она смущала, пока они не выяснили, как в нее играть. Демонстрация была короткой, но мы обнаружили, что игра понравилась довольно разношерстной публике.

Более подробную информацию о CS Connections 2018 можно найти здесь.

Рекомендуемые: