Inhoudsopgave:

Network Rivalry: een spel met lage latentie voor de BBC Micro:bit: 10 stappen (met afbeeldingen)
Network Rivalry: een spel met lage latentie voor de BBC Micro:bit: 10 stappen (met afbeeldingen)

Video: Network Rivalry: een spel met lage latentie voor de BBC Micro:bit: 10 stappen (met afbeeldingen)

Video: Network Rivalry: een spel met lage latentie voor de BBC Micro:bit: 10 stappen (met afbeeldingen)
Video: Challenges and Opportunities in Academic Research Networking 2024, Juli-
Anonim
Network Rivalry: een spel met lage latentie voor de BBC Micro:bit
Network Rivalry: een spel met lage latentie voor de BBC Micro:bit
Network Rivalry: een spel met lage latentie voor de BBC Micro:bit
Network Rivalry: een spel met lage latentie voor de BBC Micro:bit

In deze tutorial leg ik uit hoe je een basisspel voor meerdere spelers implementeert op de BBC micro:bit met de volgende functies:

  • Een eenvoudige interface
  • Lage latentie tussen het indrukken van een knop en schermupdates
  • Een flexibel aantal deelnemers
  • Eenvoudige controle over het spel met behulp van een master-afstandsbediening ("root")-apparaat

Het spel is in wezen een simulatie van politiek. Alle spelers beginnen zonder toegewezen aan een team, behalve twee spelers. Een van deze spelers wordt toegewezen aan team A en de andere wordt toegewezen aan team B.

Het doel van het spel is dat elke speler in het team zit met de meerderheid van de spelers op het moment dat iedereen wordt bekeerd.

Het bovenstaande diagram illustreert een eindige-toestandsmachine, d.w.z. een specificatie van de toestanden waarin het apparaat zich kan bevinden en de overgangen tussen die toestanden.

Een status kan worden gezien als de huidige set gegevens die het geheugen van het apparaat beschrijft sinds het is ingeschakeld. Op basis van die gegevens kan het apparaat bepaalde acties uitvoeren of anders reageren op gebruikersinvoer.

Een overgang is een logische voorwaarde die, indien waar, ervoor zorgt dat het apparaat van status verandert. Een overgang kan van de ene toestand naar een andere toestand zijn. Een toestand kan meerdere overgangen hebben.

Het bovenstaande diagram specificeert de volgende toestanden:

  • Niet toegewezen
  • Luister naar A
  • Luister naar B
  • Team A
  • Team B

Een apparaat met de spelcode kan zich in een van deze vijf toestanden bevinden, maar slechts één tegelijk en alleen deze vijf.

Ik ga er in de hele handleiding van uit dat u de MakeCode-editor van Microsoft gebruikt, die u kunt vinden op:

De volledige implementatie van het spel is hier te vinden:

makecode.microbit.org/_CvRMtheLbRR3 ("microbit-demo-user" is de projectnaam)

En implementatie van de master ("root") netwerkcontroller is hier te vinden:

makecode.microbit.org/_1kKE6TRc9TgE ("microbit-demo-root" is de projectnaam)

Ik zal in mijn tutorial naar deze voorbeelden verwijzen.

Stap 1: Overwegingen bij het ontwerpen van grote afbeeldingen

Voordat we code schrijven, moeten we nadenken over hoe we willen dat ons eindproduct eruitziet. met andere woorden, wat zijn de vereisten van de aanvraag? Wat moet onze code het apparaat vertellen om te doen als het klaar is? Ik heb de functionaliteit van de hoofdtoepassing onderverdeeld in zes categorieën, die elk vanuit een ander ontwerpperspectief kunnen worden bekeken.

  1. We willen de acties van het apparaat regelen op basis van de huidige status
  2. We willen dat het apparaat reageert op gebruikersinvoer
  3. Misschien willen we animaties en afbeeldingen weergeven met behulp van het 5 x 5 LED-display
  4. We willen gegevenswaarden in het geheugen van het apparaat initialiseren wanneer het apparaat opstart
  5. We willen gegevens draadloos verzenden via de radio van het apparaat
  6. We willen gegevens via de radio van het apparaat beluisteren en ontvangen en dienovereenkomstig verwerken

Staat u mij toe op elk daarvan iets meer in detail te treden.

1. We willen de acties van het apparaat regelen op basis van de huidige status

Net als bij de meeste andere programma's, gebeurt de uitvoering van de instructies die door de code worden gespecificeerd regel voor regel. We willen dat ons apparaat bepaalde instructies uitvoert op basis van de interne status, zoals geïllustreerd door het diagram bovenaan deze tutorial. We zouden een reeks conditionals kunnen schrijven na elk codeblok dat controleert dat het apparaat zou moeten doen, maar deze aanpak kan heel snel erg rommelig worden, dus we zullen in plaats daarvan een oneindige lus gebruiken die eenvoudig één variabele controleert, en op basis van die variabele, voert een specifieke set instructies uit of doet helemaal niets. Deze variabele wordt geïdentificeerd door het achtervoegsel "_state" in zowel onze gebruikerstoepassing als onze hoofdtoepassing.

2. We willen dat het apparaat reageert op gebruikersinvoer

Ondanks de normale uitvoering van de code die opeenvolgend plaatsvindt, dat wil zeggen regel voor regel, hebben we ons apparaat nodig om te reageren op het indrukken van een knop, terwijl de hoofdstatuslus bepaalt wat het apparaat op een bepaald moment moet doen. Voor dat doel heeft het apparaat de mogelijkheid om signalen te sturen naar de software op een lager niveau die interageert met de hardware, waardoor een zogenaamde gebeurtenis wordt geactiveerd. We kunnen code schrijven die het apparaat vertelt iets te doen wanneer het een specifiek type gebeurtenis detecteert.

3. We willen animaties en afbeeldingen weergeven met behulp van het 5 x 5 LED-display

Het mechanisme om dit te doen lijkt eenvoudig, maar het blok geeft wel een afbeelding weer en voegt een verborgen vertraging van 400 ms toe. Omdat we willen dat ons apparaat zijn statuslus blijft uitvoeren met zo min mogelijk latentie, moeten we de javascript-code bewerken om de vertraging te minimaliseren.

4. We willen gegevenswaarden in het geheugen van het apparaat initialiseren wanneer het apparaat opstart

Voordat ons apparaat iets doet, moet de applicatie zijn gegevens in het geheugen laden. Dit omvat constante variabelen die zijn genoemd vanwege de leesbaarheid van de code, variabelen die afbeeldingen bevatten, die mogelijk deel uitmaken van een animatie, en tellervariabelen die bij 0 moeten beginnen om goed te werken. We zullen eindigen met een lange lijst met namen van variabelen en hun nieuw toegewezen waarden. Als persoonlijke stijlkeuze zal ik constante waarden aangeven, d.w.z. waarden die ik nooit hoef te veranderen, met ALL_CAPS. Ik zal de identificatiecodes van de hoofdvariabelen ook vooraf laten gaan door een categorienaam die verwijst naar een soort object of type waar de identificatiecode onder valt. Dit is in een poging om de code gemakkelijker te volgen te maken. Ik zal nooit een variabelenaam zoals "item" of "x" gebruiken vanwege de dubbelzinnigheid die ontstaat wanneer ik de code probeer te ontcijferen.

5. We willen gegevens draadloos verzenden via de radio van het apparaat

Dit is eigenlijk een vrij eenvoudige taak bij het gebruik van de MakeCode-blokkentaal. We stellen eenvoudig alle apparaten in op dezelfde radiogroep tijdens het opstarten en wanneer we een signaal willen verzenden, kunnen we een enkel nummer doorgeven aan het "Radio verzendnummer"-blok dat ons is verstrekt. Het is belangrijk dat de zender en ontvanger op dezelfde radiogroep werken, want anders zullen ze op verschillende frequenties zenden of ontvangen en zal de communicatie niet succesvol zijn.

6. We willen gegevens via de radio van het apparaat beluisteren en ontvangen en dienovereenkomstig verwerken

Rekening houdend met dezelfde overwegingen als het vorige item, zullen we luisteren naar inkomende transmissies op dezelfde manier waarop we zullen luisteren naar gebruikersinvoer: met een gebeurtenishandler. We zullen een codeblok schrijven dat alle binnenkomende signalen zal onderzoeken en controleren of er actie moet worden ondernomen zonder de hoofdstatuslus te verstoren.

Daarnaast moeten we kort stilstaan bij het ontwerp van de veel eenvoudigere roottoepassing, een programma waarmee een apparaat het hele netwerk kan besturen. Ik zal hier niet veel tijd aan besteden omdat het veel eenvoudiger is dan het bovenstaande ontwerp en veel ervan is gewoon herhaling. Ik heb de functionaliteit van de wortel deice in drie categorieën verdeeld.

  1. We willen een signaal kunnen selecteren
  2. We willen een signaal kunnen verzenden

-

1. We willen een signaal kunnen selecteren

Dit kan door simpelweg een knop door de mogelijke signalen te laten lopen. Aangezien er slechts drie zijn, is deze benadering voldoende. Tegelijkertijd kunnen we een lus hebben die het geselecteerde signaal constant opnieuw weergeeft, zodat de gebruiker op een knop kan drukken en het geselecteerde signaal met zeer weinig latentie op het LED-display kan zien verschijnen.

2. We willen een signaal kunnen verzenden

Omdat er twee knoppen zijn, kunnen we er een aanwijzen voor selectie en de andere voor bevestiging. Net als de gebruikersapplicatie sturen we het signaal gewoon als een nummer over het netwerk. Er is geen andere informatie vereist.

In de volgende sectie zal ik meer vertellen over het eenvoudige signaalprotocol.

Stap 2: Het signaalprotocol: een eenvoudige taal voor netwerkcommunicatie

De volgende signalen kunnen worden gezien als de verzameling van alle mogelijke woorden die de apparaten kunnen gebruiken om met elkaar te praten. Omdat het netwerk zo eenvoudig is, valt er niet veel te zeggen, en daarom kunnen we deze drie signalen weergeven door eenvoudige gehele getallen.

0. Resetten

  • Identificatiecode in de code: SIG-R
  • Geheel getal: 0
  • Doel: vertel alle apparaten binnen bereik dat ze moeten stoppen met wat ze aan het doen zijn en doen alsof ze net zijn opgestart. Als dit signaal elk apparaat op het netwerk bereikt, wordt het hele netwerk gereset en kunnen de gebruikers een nieuw spel starten. Dit signaal kan alleen worden uitgezonden door een root-apparaat.

1. Conversie A

  • Identificatiecode in de code: SIG-A
  • Geheel getal: 1
  • Doel: vertel elk apparaat dat zich in de status LISTEN_A bevindt, zodra ze het conversiesignaal hebben ontvangen, om over te schakelen naar de status TEAM_A.

2. Conversie B

  1. Identificatiecode in de code: SIG-B
  2. Geheel getal: 2
  3. Doel: vertel elk apparaat dat zich in de status LISTEN_B bevindt, zodra ze het conversiesignaal hebben ontvangen, om over te schakelen naar de status TEAM_B.

Stap 3: We willen de acties van het apparaat controleren op basis van de huidige staat

We willen de acties van het apparaat controleren op basis van de huidige staat
We willen de acties van het apparaat controleren op basis van de huidige staat
We willen de acties van het apparaat controleren op basis van de huidige staat
We willen de acties van het apparaat controleren op basis van de huidige staat
We willen de acties van het apparaat controleren op basis van de huidige staat
We willen de acties van het apparaat controleren op basis van de huidige staat

Eindelijk kunnen we beginnen met het schrijven van code.

Open eerst een nieuw project in Make Code

  • Maak een nieuwe functie aan. Ik heb de mijnlus genoemd omdat dit de kernlus van de applicatie is
  • Voeg een lusblok toe dat voor onbepaalde tijd wordt herhaald. Ik heb while (true) gebruikt omdat een letterlijke true nooit false zal zijn, vandaar dat de besturingsstroom van de toepassing de lus nooit zal verlaten
  • Voeg voldoende if-else-blokken toe om te controleren of het apparaat zich in een van de vijf mogelijke statussen bevindt
  • Maak een variabele om de huidige apparaatstatus vast te houden
  • Variabelen maken om elk van de vijf mogelijke toestanden weer te geven

    Opmerking: het is goed dat deze variabelen nog geen toegewezen waarden hebben. Daar komen we op. Op dit punt is het belangrijker dat we schone, gemakkelijk leesbare code schrijven

  • Wijzig elke voorwaarde in de if-else-blokken om de huidige status te vergelijken met een van de mogelijke statussen
  • Voeg onderaan de if-else-blokken een pauze van een aantal milliseconden toe en maak een variabele om dat aantal vast te houden. We zullen het later initialiseren. Zorg ervoor dat de variabele een beschrijvende naam heeft, zoals tick of heartbeat. Omdat dit de kernlus van het apparaat is, bepaalt deze pauze de snelheid waarmee het apparaat de hoofdlus uitvoert, dus het is een zeer belangrijke waarde en te belangrijk om een magisch getal zonder naam te zijn.

Opmerking: maak je geen zorgen over de grijze blokken in de derde afbeelding. Ik kom daar later op terug.

Stap 4: We willen reageren op gebruikersinvoer

We willen reageren op gebruikersinvoer
We willen reageren op gebruikersinvoer
We willen reageren op gebruikersinvoer
We willen reageren op gebruikersinvoer

Nu willen we het apparaat vertellen hoe het moet omgaan met het indrukken van knoppen. Je eerste gedachte zou kunnen zijn om gewoon de "Wanneer knop wordt ingedrukt"-blokken in de invoercategorie te gebruiken, maar we zouden graag meer gedetailleerde controle willen dan dat. We zullen het blok "on event from (X) with value (Y)" uit de controlecategorie onder de geavanceerde sectie gebruiken, omdat we gevorderd zijn in deze tutorial.

  • Maak vier "op gebeurtenis van…" blokken.

    • Twee hiervan zouden de gebeurtenisbron "MICROBIT_ID_BUTTON_A" moeten controleren
    • Twee hiervan zouden de gebeurtenisbron "MICROBIT_ID_BUTTON_B" moeten controleren
    • Van de twee gebeurtenissen die op elke knop zijn gericht:

      • Men moet controleren op de gebeurtenis van het type "MICROBIT_BUTTON_EVT_UP"
      • Men moet controleren op de gebeurtenis van het type "MICROBIT_BUTTON_EVT_DOWN"
    • Opmerking: deze opties in hoofdletters zijn labels die worden gebruikt in de micro:bit-code op een lager niveau. Het zijn gewoon tijdelijke aanduidingen die later worden vervangen door gehele getallen wanneer de code wordt gecompileerd tot een uitvoerbaar binair bestand. Het is gemakkelijker voor mensen om deze labels te gebruiken dan om op te zoeken welk geheel getal ze moeten invoeren, hoewel beide op dezelfde manier zouden werken.
  • Ik heb ervoor gekozen om, als een kwestie van stijl, elk "on event from…"-blok een functie te laten aanroepen die de verhoogde gebeurtenis beschrijft. Hoewel dit niet strikt noodzakelijk is, verbetert dit naar mijn mening de leesbaarheid. Als men dit wil doen, kunnen ze de code voor het afhandelen van gebeurtenissen in het blok "on event from…" zelf plaatsen.

    Opmerking: het codeblok dat de reactie van het apparaat op een gebeurtenis afhandelt, wordt intuïtief een "event-handler" genoemd

  • Voeg in elke gebeurtenishandler dezelfde if-else-structuur toe die wordt gebruikt om de besturingsstroom te splitsen op basis van de apparaatstatus als de structuur in de hoofdstatuslus.
  • Voeg toewijzingsblokken toe die die status van het apparaat wijzigen, zoals gespecificeerd in ons statusdiagram

    • We weten dat wanneer het apparaat zich in de status UNASSIGNED bevindt, het apparaat moet reageren op knop A ingedrukt door een overgang naar toestand LISTEN_A, en op knop B ingedrukt door een overgang naar toestand LISTEN_B
    • We weten ook dat wanneer het apparaat zich in de status LISTEN_A of LISTEN_B bevindt, het apparaat moet reageren op respectievelijk knop A die wordt losgelaten en knop B wordt losgelaten door terug te gaan naar de status UNASSIGNED.
    • Ten slotte weten we dat wanneer het apparaat zich in de status TEAM_A of TEAM_B bevindt, het apparaat moet reageren op knop A die wordt ingedrukt en op knop B door respectievelijk SIG_A en SIG_B uit te zenden.

      Het is op dit moment niet nodig om de details van omroepsignalen in te vullen. Daar komen we later op terug. Wat belangrijk is, is dat we deze functies instrueren om de code te gebruiken die we zullen schrijven door dat blok met acties een naam te geven, zoals broadcastSignalSIG_A, die beschrijft wat er op dat moment moet gebeuren

Stap 5: We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart

We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart
We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart
We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart
We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart
We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart
We willen gegevenswaarden in het apparaatgeheugen initialiseren wanneer het apparaat opstart

Op dit moment hebben we veel variabelen (namen voor gegevens) gebruikt, maar we hebben eigenlijk geen waarden aan die namen toegewezen. We willen dat het apparaat de waarden van al deze variabelen in het geheugen laadt wanneer het opstart, dus plaatsen we de initialisatie voor deze variabelen in een "on start" -blok.

Dit zijn de waarden die we moeten initialiseren:

  • Signaalconstanten, volgens het signaalprotocol. De waarden MOETEN zijn:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Opmerking: ik heb deze constanten voorafgegaan door "EnumSignals" om aan te geven dat deze variabelen zich moeten gedragen alsof ze deel uitmaken van een opgesomd type genaamd Signalen. Dit is hoe deze variabelen kunnen worden geïmplementeerd in andere programmeertalen. De definitie en uitleg van opgesomde typen valt buiten het bestek van mijn tutorial. Men kan het googlen als ze dat willen. Deze voorvoegsels zijn gewoon stilistische keuzes en zijn helemaal niet essentieel voor een goede werking van het programma.
  • Geef constanten aan, die willekeurig kunnen zijn zolang ze een waarde hebben. Ik heb een stijlkeuze gemaakt om gewoon gehele getallen te gebruiken oplopend vanaf 0, zoals:

    • NIET TOEGEWEZEN = 0
    • LISTEN_A = 1
    • LISTEN_B = 2
    • TEAM_A = 3
    • TEAM_B = 4
    • Opmerking: ik heb dezelfde stijlbeslissing ook genomen met betrekking tot voorvoegsels voor deze variabelen. Daarnaast zal ik vermelden dat alles over deze opdrachten, de waarden en de volgorde, volledig willekeurig is. Het maakt niet eens uit dat deze waarden consistent zijn van apparaat tot apparaat, omdat ze alleen intern worden gebruikt en niet voor communicatie via het netwerk. Het enige dat telt is dat de variabelen een waarde hebben en dat ze met elkaar kunnen worden vergeleken om te zien of ze equivalent zijn of niet.
  • Voor de leesbaarheid, een constante genaamd BOOT_STATE en stel deze in op UNASSIGNED. Dit maakt het feit dat we resetten naar de opstartstatus, in plaats van een meer willekeurige status, explicieter wanneer het apparaat een resetsignaal ontvangt, wat we later zullen implementeren.
  • Animatieconstanten, die in de volgende stap worden gebruikt om animaties te maken die een onderbreking met extreem lage latentie mogelijk maken via gebruikersinvoer. We hebben deze tot nu toe niet gebruikt, maar ze zullen zeker worden uitgelegd en gebruikt in de volgende sectie. De betekenis van sommige hiervan zou intuïtief moeten zijn vanwege hun naam.

    • 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
  • Nog een variabele voor animatie, dit keer een teller die zeker niet constant is. Zoals de meeste tellers, initialiseren we het op 0

    iTickLoadingAnimation = 0

  • Maak twee reeksen variabelen om frames van animaties vast te houden. De eerste, die ik de "laadanimatie" noem, zou vier afbeeldingen moeten hebben (wat je misschien al geraden had door de laatste constante initialisatie), en de tweede, die ik de "uitzendanimatie" noem, die drie afbeeldingen zou moeten hebben. Ik raad aan om de variabelen een naam te geven die overeenkomt met frames van de animatie, b.v. ringAnimation0, ringAnimation1…

    Maak dezelfde afbeeldingswaarden als ik of creëer originelere en coolere afbeeldingen

  • Last but not least moeten we de radiogroep van het apparaat op 0 zetten met behulp van het blok "radiosetgroep (X)"
  • Schrijf optioneel het bericht "Initialisatie voltooid" naar de seriële uitvoer om de gebruiker te vertellen dat alles vlot is verlopen.
  • Nu we klaar zijn met het instellen van het apparaat, kunnen we onze statuslusfunctie aanroepen.

Stap 6: We willen animaties en afbeeldingen weergeven met behulp van het 5 x 5 LED-display

We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display
We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display
We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display
We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display
We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display
We willen animaties en afbeeldingen weergeven met behulp van het 5 X 5 LED-display

En nu voor iets compleet anders.

We willen een paar animaties en een paar karakters weergeven, maar we willen de hoofdstatuslus niet onderbreken. Helaas hebben de blokken die afbeeldingen en tekststrings weergeven standaard een vertraging van 400 ms. Er is geen manier om dit te veranderen zonder de javascript-representatie van de code te bewerken. Dit gaan we dus doen.

  • Maak een functie voor elke afbeelding. Hierdoor kan men een enkel blok gebruiken om de afbeelding weer te geven in plaats van elke keer javascript te bewerken. In dit specifieke programma wordt geen enkele afbeelding meer dan één keer gebruikt, maar ik denk nog steeds dat deze stijl de code leesbaarder maakt.
  • Voeg in elke nieuwe functie een blok "toon afbeelding (X) op offset 0" toe, waarbij de overeenkomstige naam van de afbeeldingsvariabele wordt vervangen door (X)
  • Toevoegen, in de hoofdstatuslus. "Toon tekenreeks (X)" -blokken aan elk blok behalve het blok dat de status UNASSIGNED afhandelt. Voeg een teken toe dat het apparaat moet weergeven om de verschillende statussen aan te geven. Dit is wat ik deed:

    • LISTEN_A: 'een'
    • LISTEN_B: 'b'
    • TEAM_A: 'A'
    • TEAM_B: 'B'

      Plaats voor de status UNASSIGNED een aanroep van een functie die de laadanimatie bijwerkt. Hieronder zullen we de details van deze functie invullen

  • Schakel over naar javascript-modus.
  • Vind elke oproep naar X.showImage(0) en basic.showString(X)
  • Verander ze allemaal in X.showImage(0, 0) of basic.showString(X, 0)

    • Door dit extra argument toe te voegen, wordt de vertraging na de actie op 0 gezet. Standaard wordt dit weggelaten en het apparaat pauzeert 400 ms na de uitvoering van elk van deze blokken.
    • Nu hebben we een bijna latentievrij mechanisme om onze afbeeldingen weer te geven in onze animatieblokken, die we nu kunnen bouwen

Eerst zullen we de relatief eenvoudige uitzendanimatiefunctie bouwen. Het is eenvoudiger omdat we niet willen dat de gebruiker iets kan doen totdat de functie is voltooid, om te voorkomen dat hij de uitzendfunctie spamt. Om dit te bereiken, kunnen we de controlestroom eenvoudig beperken tot het blok totdat de functie is voltooid, wat standaardgedrag is.

  • Maak een functie die uitzendanimatie weergeeft.
  • Voeg binnen dat blok drie functieaanroepen toe, één aan elk frame van de animatie, in de volgorde waarin ze moeten worden weergegeven
  • Voeg na elke aanroep een "wait (us) (X)" -blok toe aan een functie voor het weergeven van afbeeldingen.

    Opmerking: dit blok, van het gedeelte voor geavanceerde besturing, gaat zelfs verder dan "pauze (ms)" omdat het de processor volledig zal bevriezen totdat de opgegeven tijd is verstreken. Bij gebruik van het pauzeblok is het mogelijk dat het toestel achter de schermen andere taken gaat uitvoeren. Dit is onmogelijk met het wachtblok

  • Vervang (X) door (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • De animatie zou nu goed moeten werken

Ten tweede zullen we het mechanisme bouwen voor het weergeven van de laadanimatie. Het idee hierachter is om het LED-display bij te werken met een specifiek interval, dat we definiëren in de variabele MS_PER_DEVICE_TICK. Deze waarde, de tick-lengte van het apparaat, is het aantal milliseconden dat het apparaat pauzeert na het voltooien van elke iteratie van de statuslus. Omdat deze waarde klein genoeg is, kunnen we de weergave eenmaal bijwerken tijdens elke iteratie van de weergavelus en zal het voor de gebruiker lijken dat de animatie naadloos verloopt, en wanneer de status verandert, zal er zeer weinig latentie zijn tussen de invoer van de gebruiker het scherm wordt bijgewerkt. Door ticks te tellen, wat we doen met de variabele iTickLoadingAnimation, kunnen we het juiste frame van de animatie weergeven.

  • Maak een functie die de laadanimatie bijwerkt
  • Voeg een voorwaarde toe om te controleren of de tekenteller zijn maximale waarde heeft bereikt. Deze voorwaarde is waar als de waarde van de tick-teller groter is dan het aantal frames in de laadanimatie vermenigvuldigd met het aantal ticks om elk frame weer te geven

    Als de voorwaarde waar is, stelt u iTickLoadingAnimation opnieuw in op 0

  • Voeg een blok met if-else-voorwaarden toe. Deze bepalen welk frame van de animatie moet worden weergegeven.

    Voor elk frame van de animatie, als de tick-teller minder is dan het aantal ticks in elke animatie vermenigvuldigd met het framenummer van de animatie (beginnend bij 1), geef dan dat frame weer, controleer anders of het volgende frame het frame is dat moet worden weergegeven. tentoongesteld zijn

  • Verhoog onder aan het blok iTickLoadingAnimation
  • De animatie zou nu goed moeten werken

Opmerking: alle grijze blokken die in mijn voorbeeld verschijnen, worden gegenereerd wanneer men de javascript-representatie van een blok bewerkt. Het betekent eenvoudigweg dat het blok javascript-code vertegenwoordigt die niet kan worden weergegeven met de standaardset blokken en in tekstvorm moet worden bewerkt.

Stap 7: We willen gegevens draadloos verzenden via de radio van het apparaat

We willen gegevens draadloos verzenden met de radio van het apparaat
We willen gegevens draadloos verzenden met de radio van het apparaat

Deze stap is veel korter dan de vorige. In feite is het waarschijnlijk de kortste stap in deze hele tutorial.

Bedenk dat toen we de reactie van het apparaat op gebruikersinvoer programmeerden, ik twee blokken in de schermafbeelding had die niet in die sectie werden uitgelegd. Dit waren oproepen naar functies die signalen via de radio verzenden. Specifieker:

  • Op knop A ingedrukt:

    • Als het apparaat zich in de status TEAM_A bevindt:

      Uitzendsignaal SIG_A

  • Op knop B ingedrukt:

    • Als het apparaat zich in de status TEAM_B. bevindt

      Uitzendsignaal SIG_B

Maak deze functies als ze nog niet bestaan.

In elke functie:

  • Roep de uitzendanimatiefunctie op. Hiermee wordt voorkomen dat er iets anders gebeurt totdat het is voltooid, wat in MS_PER_FRAME_BROADCAST_ANIMATION * 3 = 1,5 seconde zal zijn. De constante wordt met drie vermenigvuldigd omdat er drie frames in de animatie zijn. Dit is willekeurig en er kan meer worden toegevoegd als de esthetische upgrade groot genoeg is. Een tweede doel van deze animatie is om te voorkomen dat een gebruiker de uitzendfunctie spamt.
  • Voeg een "radio verzendnummer (X)" -blok toe, waar de signaalconstante wordt vermeld in de functienaam

Dat is alles wat je nodig hebt om via de radio uit te zenden.

Stap 8: We willen naar de radio van het apparaat luisteren en gegevens ontvangen en dienovereenkomstig verwerken

We willen naar gegevens luisteren en deze ontvangen via de radio van het apparaat en dienovereenkomstig verwerken
We willen naar gegevens luisteren en deze ontvangen via de radio van het apparaat en dienovereenkomstig verwerken
We willen naar gegevens luisteren en deze ontvangen via de radio van het apparaat en dienovereenkomstig verwerken
We willen naar gegevens luisteren en deze ontvangen via de radio van het apparaat en dienovereenkomstig verwerken

Dit is de laatste stap om de hoofdtoepassing te maken.

We gaan het apparaat vertellen hoe binnenkomende radiosignalen moeten worden verwerkt. Eerst gaat ons apparaat het ontvangen signaal een naam geven. Vervolgens zal het, op basis van de waarde van dat signaal, beslissen welke actie moet worden ondernomen, indien van toepassing.

Eerst:

  1. Maak een codeblok dat begint met een blok "op radio ontvangen (X)".
  2. Wijs desgewenst die ontvangen waarde toe aan een andere variabele met een meer beschrijvende naam.
  3. Roep een functie aan die het signaal zal verwerken

Ten tweede, in de signaalverwerkingsfunctie:

  1. Maak een blok met if-else-instructies die de controlestroom vertakken op basis van de waarde van het signaal.
  2. Als het signaal SIG_R. was

    Stel de status van het apparaat in op BOOT_STATE (daarom hebben we deze constante eerder gemaakt)

  3. Als het signaal SIG_A was en als de huidige status LISTEN_A. is

    Stel de status van het apparaat in op TEAM_A

  4. Als het signaal SIG_B was en als de huidige status LISTEN_B. is

    Stel de status van het apparaat in op TEAM_B

Dat is het. De aanvraag is klaar.

Stap 9: Root-apparaat: we willen een signaal kunnen selecteren

Root-apparaat: we willen een signaal kunnen selecteren
Root-apparaat: we willen een signaal kunnen selecteren

Nu zullen we een eenvoudige applicatie schrijven voor een "root"-apparaat, dat wil zeggen een apparaat dat het netwerk zal besturen.

Dit apparaat moet twee functies vervullen:

  • We willen de gebruiker toestaan om een van onze signalen te selecteren
  • We willen de gebruiker toestaan het signaal uit te zenden

Omdat de specificatie van deze applicatie een subset is van de vorige, zal ik een overzicht geven, maar ik zal niet zo gedetailleerd ingaan als ik eerder had. De afbeelding hierboven bevat de volledige code voor deze toepassing.

Om de gebruiker een signaal te laten selecteren:

  1. Initialiseer 5 variabelen in een "on start" -blok:

    1. De drie signalen (0, 1, 2)
    2. Het aantal signalen (3)
    3. Een variabele om het momenteel geselecteerde signaal vast te houden (aanvankelijk ingesteld op het eerste signaal, 0)
  2. Behandel een druk op de A-knop:

    1. Verhoog het geselecteerde signaal
    2. Controleer of het geselecteerde signaal groter is dan of gelijk is aan het aantal signalen

      Zo ja, stel dan het geselecteerde signaal in op 0

  3. Voer na het aan-startblok een "voor altijd" lus uit die de huidige geselecteerde signaalwaarde zonder vertraging weergeeft

Om de gebruiker in staat te stellen een signaal uit te zenden

  1. Zet de radiogroep op 0 in het "aan start"-blok
  2. Behandel een druk op de B-knop:

    Zend het geselecteerde signaal uit met een "radio verzendnummer (X)" blok

Dat is het. De toepassing van het rootknooppunt is uiterst eenvoudig.

Stap 10: We zijn klaar

We zijn klaar
We zijn klaar

Hierboven ziet u een afbeelding van de apparaten waarop de toepassing wordt uitgevoerd. De twee aan de rechterkant draaien de hoofdtoepassing "gebruiker", en die aan de linkerkant draait de "root"-toepassing.

Ik heb deze game gedemonstreerd op CS Connections 2018, een zomerconferentie van een week voor leraren in het middelbaar en middelbaar onderwijs over informaticaonderwijs. Ik deelde ongeveer 40 apparaten uit aan de leraren en legde de regels uit. De meesten vonden het spel vermakelijk, en velen vonden het verwarrend totdat ze ontdekten hoe ze moesten spelen. De demonstratie was kort, maar we vonden het spel leuk onder een redelijk divers publiek.

Meer informatie over CS Connections 2018 vind je hier.

Aanbevolen: