Съдържание:

Мрежово съперничество: игра с ниска латентност за BBC Micro: бит: 10 стъпки (със снимки)
Мрежово съперничество: игра с ниска латентност за BBC Micro: бит: 10 стъпки (със снимки)

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

Видео: Мрежово съперничество: игра с ниска латентност за BBC Micro: бит: 10 стъпки (със снимки)
Видео: TP-Link #UNBOXING | Archer GX90 - AX6600 Wi-Fi 6 трилентов гейминг рутер 2024, Юли
Anonim
Мрежово съперничество: игра с ниска латентност за BBC Micro: bit
Мрежово съперничество: игра с ниска латентност за BBC Micro: bit
Мрежово съперничество: игра с ниска латентност за BBC Micro: bit
Мрежово съперничество: игра с ниска латентност за BBC Micro: bit

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

  • Прост интерфейс
  • Ниска латентност между натискането на бутони и актуализациите на екрана
  • Гъвкав брой участници
  • Лесен контрол върху играта с помощта на главно дистанционно ("root") устройство

Играта по същество е симулация на политика. Всички играчи започват неназначени за нито един отбор, с изключение на двама играчи. Един от тези играчи е назначен за отбор А, а другият е отреден за отбор В.

Целта на играта е всеки играч да бъде в отбора с мнозинството от играчите в момента, в който всички са преобразувани.

Диаграмата по -горе илюстрира машина с крайни състояния, т.е. спецификация на състоянията, в които устройството може да бъде, и преходите между тези състояния.

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

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

Диаграмата по -горе определя следните състояния:

  • Неназначен
  • Слушайте за А.
  • Слушайте B
  • Отбор А
  • Екип Б

Устройство, работещо с кода на играта, може да бъде в някое от тези пет състояния, но само едно по едно и само тези пет.

Ще приема в цялото ръководство, че използвате редактора на Microsoft MakeCode, който може да бъде намерен на:

Пълното изпълнение на играта можете да намерите тук:

makecode.microbit.org/_CvRMtheLbRR3 ("microbit-demo-user" е името на проекта)

А изпълнението на главния ("root") мрежов контролер може да се намери тук:

makecode.microbit.org/_1kKE6TRc9TgE ("microbit-demo-root" е името на проекта)

Ще се позова на тези примери в целия си урок.

Стъпка 1: Съображения за дизайн на голяма картина

Преди да напишем някакъв код, трябва да помислим как искаме да изглежда крайният ни продукт. с други думи, какви са изискванията на заявлението? Какво трябва да каже нашият код на устройството, след като приключи? Разделих функционалността на основното приложение в шест категории, всяка от които може да се разглежда от различна дизайнерска гледна точка.

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

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

1. Искаме да контролираме действията на устройството въз основа на текущото му състояние

Подобно на повечето други програми, изпълнението на инструкциите, посочени в кода, се случва по един ред. Искаме нашето устройство да изпълнява определени инструкции въз основа на вътрешното си състояние, както е показано на диаграмата в горната част на този урок. Бихме могли да напишем поредица от условни условия след всеки блок код, който проверява устройството, което трябва да прави, но този подход може да стане много объркан много бързо, така че вместо това ще използваме безкраен цикъл, който просто проверява една променлива и въз основа на тази променлива, изпълнява определен набор от инструкции или не прави нищо. Тази променлива ще бъде идентифицирана чрез наставката "_state" както в нашето потребителско приложение, така и в нашето root приложение.

2. Искаме устройството да реагира на въвеждане от потребителя

Въпреки нормалното изпълнение на кода, което се случва последователно, тоест по един ред, ние се нуждаем от нашето устройство, за да реагира на натискане на бутони, докато основният цикъл на състоянието определя какво трябва да направи устройството във всеки един момент. За тази цел устройството има възможност да изпраща сигнали към софтуера от по-ниско ниво, който взаимодейства с хардуера, задействайки това, което се нарича събитие. Можем да напишем код, който казва на устройството да направи нещо, когато открие определен тип събитие.

3. Искаме да показваме анимации и графики, използвайки 5 x 5 LED дисплея

Изглежда, че механизмът за това е прост, но блокът показва изображение добавя скрито забавяне от 400 ms. Тъй като искаме нашето устройство да продължи да изпълнява своя цикъл на състояние с възможно най -малко латентност, ще трябва да редактираме кода на javascript, за да намалим забавянето.

4. Искаме да инициализираме стойностите на данните в паметта на устройството, когато устройството се зарежда

Преди нашето устройство да направи нещо, приложението трябва да зареди данните си в паметта. Това включва константни променливи, наречени за четимост на кода, променливи, които съдържат изображения, които може да са част от анимация, и променливи на брояча, които трябва да започнат с 0, за да работят правилно. Ще завършим с дълъг списък с имена на променливи и техните новоприсвоени стойности. Като избор на личен стил, ще обозначавам постоянни стойности, т.е. стойности, които никога няма да се налага да променя, използвайки ALL_CAPS. Също така ще поставя префикс за основните идентификатори на променливи с име на категория, което се отнася до един вид обект или тип, под който идентификаторът попада. Това се опитва да направи кода по -лесен за следване. Никога няма да използвам име на променлива като "item" или "x" поради неяснотата, която възниква при опит за дешифриране на кода.

5. Искаме да предаваме данни безжично, използвайки радиото на устройството

Това всъщност е доста проста задача, когато използвате езика на блоковете MakeCode. Ние просто настройваме всички устройства към една и съща радио група по време на зареждане и след това, когато искаме да изпратим сигнал, можем да предадем един номер на предоставения ни блок „Номер за радио изпращане“. Важно е изпращачът и получателят да работят на една и съща радио група, защото ако не, те ще изпращат или получават на различни честоти и комуникацията ще бъде неуспешна.

6. Искаме да изслушваме и получаваме данни по радиото на устройството и да ги обработваме съответно

Имайки предвид същите съображения като предишния елемент, ние ще слушаме входящите предавания по същия начин, по който ще слушаме въвеждането от потребителя: с манипулатор на събития. Ще напишем блок код, който ще изследва всички входящи сигнали и ще проверява дали трябва да се предприемат някакви действия, без да се нарушава основният цикъл на състоянието.

Освен това трябва накратко да разгледаме дизайна на далеч по -простото root приложение, програма, която ще позволи на устройство да контролира цялата мрежа. Няма да отделям много време за това, тъй като е много по -просто от горния дизайн и голяма част от него е просто повторение. Разделих функционалността на root deice в три категории.

  1. Искаме да можем да избираме сигнал
  2. Искаме да можем да предаваме сигнал

-

1. Искаме да можем да избираме сигнал

Това може да стане, като просто натиснете бутон, който да променя възможните сигнали. Тъй като има само три, този подход ще бъде достатъчен. В същото време можем да имаме цикъл, който постоянно изобразява отново избрания сигнал, позволявайки на потребителя да натисне бутон и да види избрания сигнал да се появява на LED дисплея с много малко закъснение.

2. Искаме да можем да предаваме сигнал

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

Ще говоря повече за простия протокол за сигнали в следващия раздел.

Стъпка 2: Протоколът за сигнали: прост език за мрежова комуникация

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

0. Нулиране

  • Идентификатор в кода: SIG-R
  • Целочислена стойност: 0
  • Предназначение: Кажете на всички устройства в обхвата да се откажат от това, което правят, и да се държат така, сякаш току -що са стартирани. Ако този сигнал достигне до всяко устройство в мрежата, цялата мрежа ще бъде нулирана и потребителите могат да започнат нова игра. Този сигнал може да се излъчва само от коренно устройство.

1. Преобразуване А

  • Идентификатор в кода: 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)" от категорията за управление в раздела Advanced, тъй като в този урок сме напреднали.

  • Създайте четири блока "на събитие от …".

    • Две от тях трябва да проверят източника на събитие „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, устройството трябва да реагира съответно на освободен бутон А и освободен бутон В, като премине обратно в състояние НЕПРЕДЕЛЕНО.
    • И накрая, ние знаем, че когато устройството е в състояние TEAM_A или TEAM_B, устройството трябва да реагира на натиснат бутон A и бутон B натиснат съответно от излъчването SIG_A и от излъчването SIG_B.

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

Стъпка 5: Искаме да инициализираме стойностите на данните в паметта на устройствата, когато устройството се стартира

Искаме да инициализираме стойностите на данните в паметта на устройствата при зареждане на устройството
Искаме да инициализираме стойностите на данните в паметта на устройствата при зареждане на устройството
Искаме да инициализираме стойностите на данните в паметта на устройствата при зареждане на устройството
Искаме да инициализираме стойностите на данните в паметта на устройствата при зареждане на устройството
Искаме да инициализираме стойностите на данните в паметта на устройствата, когато устройството се стартира
Искаме да инициализираме стойностите на данните в паметта на устройствата, когато устройството се стартира

На този етап сме използвали много променливи (имена за данни), но всъщност не сме присвоили стойности на тези имена. Искаме устройството да зареди стойностите на всички тези променливи в паметта, когато се зарежда, затова поставяме инициализацията за тези променливи в блок "при стартиране".

Това са стойностите, които трябва да инициализираме:

  • Сигнални константи, според сигналния протокол. Стойностите ТРЯБВА да бъдат:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Забележка: Представих тези константи с "EnumSignals", за да отбележа, че тези променливи трябва да се държат така, сякаш са част от изброен тип, наречен Signals. Ето как тези променливи могат да бъдат внедрени в други езици за програмиране. Определението и обяснението на изброените типове е извън обхвата на моя урок. Човек може да го потърси в Google, ако желае. Тези префикси са просто стилистични избори и изобщо не са от съществено значение за правилното функциониране на програмата.
  • Константи на състоянието, които могат да бъдат произволни, стига да имат стойност. Направих избор на стил просто да използвам цели числа, възходящи от 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, като използваме блока "група радиостанции (X)"
  • По желание напишете съобщението „Инициализацията завършена“към серийния изход, за да кажете на потребителя, че всичко е минало плавно.
  • Сега, когато приключихме с настройката на устройството, можем да извикаме нашата функция за цикъл на състояние.

Стъпка 6: Искаме да покажем анимации и графики с помощта на 5 X 5 LED дисплея

Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея
Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея
Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея
Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея
Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея
Искаме да показваме анимации и графики с помощта на 5 X 5 LED дисплея

А сега за нещо съвсем различно.

Искаме да покажем няколко анимации и няколко знака, но не искаме да прекъсваме главния цикъл на състоянието. За съжаление, блоковете, които показват изображения и текстови низове, имат забавяне от 400 ms по подразбиране. Няма начин да промените това, без да редактирате javascript представянето на кода. И така, това ще направим.

  • Създайте функция за всяко изображение. Това ще позволи на човек да използва един блок за показване на изображението, вместо да редактира javascript всеки път. В тази конкретна програма нито едно изображение не се използва повече от веднъж, но все пак мисля, че този стил прави кода по -лесен за четене.
  • Добавете във всяка нова функция блок „показване на изображението (X) при отместване 0“със съответното име на променливата на изображението, заместващо (X)
  • Добавете в основния цикъл на състоянието. Блоковете „Показване на низ (X)“към всеки блок, освен този, който обработва състояние НЕПРЕДЕЛЕНО. Добавете знак, който устройството да покаже, за да посочи различните му състояния. Ето какво направих:

    • LISTEN_A: 'а'
    • LISTEN_B: 'b'
    • TEAM_A: 'А'
    • TEAM_B: 'B'

      За състояние UNASSIGNED, обадете се на функция, която ще актуализира анимацията за зареждане. По -долу ще попълним подробностите за тази функция

  • Превключете в режим на JavaScript.
  • Намерете всяко обаждане до X.showImage (0) и basic.showString (X)
  • Променете всеки един на X.showImage (0, 0) или basic.showString (X, 0)

    • Добавянето на този допълнителен аргумент ще зададе забавянето след действието на 0. По подразбиране това е пропуснато и устройството ще направи пауза за 400 ms след изпълнението на всеки от тези блокове.
    • Сега имаме механизъм почти без латентност за показване на нашите изображения в нашите анимационни блокове, които вече можем да изградим

Първо, ще изградим сравнително простата функция за анимация при излъчване. Това е по -просто, защото не искаме потребителят да може да прави каквото и да е, докато функцията не бъде завършена, така че да го спре да спами функцията за излъчване. За да постигнем това, можем просто да поддържаме контролния поток ограничен до блока, докато функцията приключи, което е стандартно поведение.

  • Създайте функция, която ще показва анимация за излъчване.
  • Вътре в този блок добавете три извиквания на функции, по един към всеки кадър от анимацията, в реда, в който трябва да се показват
  • Добавете блок "чакане (нас) (X)" след всяко извикване към функция за показване на изображения.

    Забележка: Този блок, от раздела за разширено управление, ще отиде дори по -далеч от "пауза (мс)", тъй като напълно ще замрази процесора, докато не изтече определеното време. Когато се използва блокът за пауза, е възможно устройството да изпълнява други задачи зад кулисите. Това е невъзможно с блока за изчакване

  • Заменете (X) с (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • Анимацията вече трябва да функционира правилно

Второ, ще изградим механизма за показване на анимацията за зареждане. Идеята зад това е да актуализираме LED дисплея на определен интервал, който дефинираме в променливата MS_PER_DEVICE_TICK. Тази стойност, дължината на отметката на устройството, е броят на милисекундите, които устройството спира на пауза след завършване на всяка итерация на цикъла на състоянието. Тъй като тази стойност е достатъчно малка, можем да актуализираме дисплея веднъж по време на всяка итерация на цикъла на показване и на потребителя ще изглежда, че анимацията се развива безпроблемно и когато състоянието се промени, ще има много малко закъснение между въвеждането от потребителя дисплеят се актуализира. Чрез преброяване на отметките, което правим с променливата iTickLoadingAnimation, можем да покажем подходящата рамка на анимацията.

  • Създайте функция, която ще актуализира зареждащата анимация
  • Добавете условие, за да проверите дали броячът на кърлежи е достигнал максималната си стойност. Това условие ще бъде вярно, ако стойността на брояча е по -голяма от броя на кадрите в анимацията за зареждане, умножена по броя на отметките за показване на всеки кадър

    Ако условието е вярно, нулирайте iTickLoadingAnimation на 0

  • Добавете блок от условия if-else. Те ще определят коя рамка от анимацията да се показва.

    За всеки кадър от анимацията, ако броячът на отметките е по -малък от броя на отметките във всяка анимация, умножен по номера на кадъра на анимацията (започващ от 1), след това покажете този кадър, в противен случай проверете дали следващият кадър е този за да се покаже

  • В долната част на блока увеличете iTickLoadingAnimation
  • Анимацията вече трябва да функционира правилно

Забележка: Всички сиви блокове, които се появяват в моя пример, се генерират, когато човек редактира javascript представянето на блок. Това просто означава, че блокът представлява код на javascript, който не може да бъде представен с помощта на стандартния набор от блокове и трябва да бъде редактиран в текстова форма.

Стъпка 7: Искаме да предаваме данни безжично, използвайки радиото на устройството

Искаме да предаваме данни безжично, използвайки радиото на устройството
Искаме да предаваме данни безжично, използвайки радиото на устройството

Тази стъпка е много по -кратка от предишната. Всъщност това е може би най -кратката стъпка в целия този урок.

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

  • Бутонът за включване A натиснат:

    • Ако устройството е в състояние TEAM_A:

      Излъчващ сигнал SIG_A

  • Натиснат бутон В:

    • Ако устройството е в състояние 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: Основно устройство: Искаме да можем да изберем сигнал

Кореново устройство: Искаме да можем да избираме сигнал
Кореново устройство: Искаме да можем да избираме сигнал

Сега ще напишем просто приложение за "root" устройство, тоест устройство, което ще контролира мрежата.

Това устройство ще трябва да изпълнява две функции:

  • Искаме да позволим на потребителя да избере един от нашите сигнали
  • Искаме да позволим на потребителя да излъчва сигнала

Тъй като спецификацията на това приложение е подмножество на предишното, ще дам преглед, но няма да навлизам в толкова подробности, колкото преди. Изображението по -горе съдържа пълния код за това приложение.

За да позволите на потребителя да избере сигнал:

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

    1. Трите сигнала (0, 1, 2)
    2. Броят на сигналите (3)
    3. Променлива за задържане на избрания в момента сигнал (първоначално зададен на първия сигнал, 0)
  2. Натиснете бутона A с едно натискане:

    1. Увеличете избрания сигнал
    2. Проверете дали избраният сигнал е по -голям или равен на броя на сигналите

      Ако е така, задайте избрания сигнал на 0

  3. След блока при стартиране стартирайте "завинаги" цикъл, който показва текущата избрана стойност на сигнала без забавяне

За да позволите на потребителя да излъчва сигнал

  1. Задайте радио групата на 0 в блока "при стартиране"
  2. Натиснете бутона B с едно натискане:

    Излъчете избрания сигнал, като използвате блок "номер за радио изпращане (X)"

Това е. Приложението за корен възел е изключително просто.

Стъпка 10: Ние сме готови

Ние сме Готови
Ние сме Готови

По -горе е снимка на устройствата, работещи с приложението. Двете вдясно изпълняват основното "потребителско" приложение, а това вляво изпълнява "root" приложението.

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

Повече информация за CS Connections 2018 можете да намерите тук.

Препоръчано: