Índice:

Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit: 10 etapas (com imagens)
Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit: 10 etapas (com imagens)

Vídeo: Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit: 10 etapas (com imagens)

Vídeo: Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit: 10 etapas (com imagens)
Vídeo: TODO MUNDO QUER ESSE HEADSET GAMER HAVIT! POR R$150 VALE A PENA? ANÁLISE H2002D 2024, Novembro
Anonim
Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit
Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit
Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit
Rivalidade de rede: um jogo de baixa latência para a BBC Micro: bit

Neste tutorial, explicarei como implementar um jogo multijogador básico na BBC micro: bit com os seguintes recursos:

  • Uma interface simples
  • Baixa latência entre pressionamentos de botão e atualizações de tela
  • Um número flexível de participantes
  • Controle fácil sobre o jogo usando um dispositivo remoto mestre ("root")

O jogo é essencialmente uma simulação de política. Todos os jogadores começam não atribuídos a nenhuma equipe, exceto para dois jogadores. Um desses jogadores é atribuído à equipe A e o outro é atribuído à equipe B.

O objetivo do jogo para cada jogador é estar no time com a maioria dos jogadores no momento em que todos se convertem.

O diagrama acima ilustra uma máquina de estado finito, ou seja, uma especificação dos estados em que o dispositivo pode estar e as transições entre esses estados.

Um estado pode ser considerado o conjunto atual de dados que descreve a memória do dispositivo desde que foi ligado. Com base nesses dados, o dispositivo pode executar certas ações ou reagir de forma diferente à entrada do usuário.

Uma transição é uma condição lógica que, quando verdadeira, faz com que o dispositivo mude de estado. Uma transição pode ser de um estado para qualquer outro estado. Um estado pode ter várias transições.

O diagrama acima especifica os seguintes estados:

  • Não atribuído
  • Ouça A
  • Ouça B
  • Equipe A
  • Time B

Um dispositivo que executa o código do jogo pode estar em qualquer um desses cinco estados, mas apenas um de cada vez e apenas esses cinco.

Presumirei ao longo do guia que você está usando o editor MakeCode da Microsoft, que pode ser encontrado em:

A implementação completa do jogo pode ser encontrada aqui:

makecode.microbit.org/_CvRMtheLbRR3 ("microbit-demo-user" é o nome do projeto)

E a implementação do controlador de rede mestre ("raiz") pode ser encontrada aqui:

makecode.microbit.org/_1kKE6TRc9TgE ("microbit-demo-root" é o nome do projeto)

Vou me referir a esses exemplos ao longo de meu tutorial.

Etapa 1: Considerações sobre o design do panorama geral

Antes de escrever qualquer código, precisamos pensar sobre como queremos a aparência do nosso produto final. em outras palavras, quais são os requisitos do aplicativo? O que nosso código deve dizer ao dispositivo para fazer quando terminar? Eu dividi a funcionalidade do aplicativo principal em seis categorias, cada uma das quais pode ser considerada de uma perspectiva de design diferente.

  1. Queremos controlar as ações do dispositivo com base em seu estado atual
  2. Queremos que o dispositivo reaja à entrada do usuário
  3. Podemos querer exibir animações e gráficos usando a tela LED 5 x 5
  4. Queremos inicializar os valores de dados na memória do dispositivo quando o dispositivo for inicializado
  5. Queremos transmitir dados sem fio usando o rádio do dispositivo
  6. Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo

Permitam-me entrar em detalhes um pouco mais sobre cada um.

1. Queremos controlar as ações do dispositivo com base em seu estado atual

Como a maioria dos outros programas, a execução das instruções especificadas pelo código ocorre uma linha por vez. Queremos que nosso dispositivo execute certas instruções com base em seu estado interno, conforme ilustrado pelo diagrama no topo deste tutorial. Poderíamos escrever uma série de condicionais após cada bloco de código que verifica o dispositivo deveria estar fazendo, mas esta abordagem pode ficar muito confusa muito rapidamente, então, em vez disso, usaremos um loop infinito que simplesmente verifica uma variável e com base nessa variável, executa um conjunto específico de instruções ou não faz nada. Esta variável será identificada pelo sufixo "_state" em nosso aplicativo de usuário e em nosso aplicativo raiz.

2. Queremos que o dispositivo reaja à entrada do usuário

Apesar da execução normal do código ocorrer sequencialmente, ou seja, uma linha por vez, precisamos que nosso dispositivo reaja aos pressionamentos de botão enquanto o loop de estado principal está determinando o que o dispositivo deve fazer a qualquer momento. Para isso, o dispositivo tem a capacidade de enviar sinais para o software de nível inferior que interage com o hardware, disparando o que se chama de evento. Podemos escrever um código que diga ao dispositivo para fazer algo ao detectar um tipo específico de evento.

3. Queremos exibir animações e gráficos usando o display LED 5 x 5

O mecanismo para fazer isso parece ser simples, mas o bloco exibe uma imagem adiciona um atraso oculto de 400 ms. Como queremos que nosso dispositivo continue a executar seu loop de estado com o mínimo de latência possível, precisaremos editar o código javascript para minimizar o atraso.

4. Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado

Antes que nosso dispositivo faça qualquer coisa, o aplicativo precisa carregar seus dados na memória. Isso inclui variáveis constantes nomeadas para legibilidade do código, variáveis que contêm imagens, que podem fazer parte de uma animação, e variáveis de contador que precisam começar em 0 para funcionar corretamente. Terminaremos com uma longa lista de nomes de variáveis e seus valores recém-atribuídos. Como uma escolha de estilo pessoal, denotarei valores constantes, ou seja, valores que nunca precisarei alterar, usando ALL_CAPS. Também prefixarei os identificadores de variáveis principais com um nome de categoria que se refere a um tipo de objeto ou tipo no qual o identificador se enquadra. Isso é uma tentativa de tornar o código mais fácil de seguir. Nunca usarei um nome de variável como "item" ou "x" por causa da ambigüidade que surge ao tentar decifrar o código.

5. Queremos transmitir dados sem fio usando o rádio do dispositivo

Esta é realmente uma tarefa bastante simples ao usar a linguagem de blocos MakeCode. Simplesmente configuramos todos os dispositivos para o mesmo grupo de rádio no momento da inicialização e, em seguida, quando quisermos enviar um sinal, podemos passar um único número para o bloco "Número de envio de rádio" fornecido para nós. É importante que o emissor e o receptor estejam trabalhando no mesmo grupo de rádio, porque senão eles estarão enviando ou recebendo em frequências diferentes, e a comunicação não terá sucesso.

6. Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo

Levando em consideração as mesmas considerações do item anterior, ouviremos as transmissões de entrada da mesma forma que ouviremos a entrada do usuário: com um manipulador de eventos. Vamos escrever um bloco de código que examinará quaisquer sinais de entrada e verificaremos se alguma ação deve ser executada sem perturbar o loop de estado principal.

Além disso, devemos considerar brevemente o design do aplicativo raiz, muito mais simples, um programa que permitirá a um dispositivo controlar toda a rede. Não vou gastar muito tempo nisso, pois é muito mais simples do que o design acima e muito dele é simplesmente repetição. Dividi a funcionalidade do dispositio raiz em três categorias.

  1. Queremos ser capazes de selecionar um sinal
  2. Queremos ser capazes de transmitir um sinal

-

1. Queremos ser capazes de selecionar um sinal

Isso pode ser feito simplesmente com um botão que itera através dos sinais possíveis. Como existem apenas três, essa abordagem será suficiente. Ao mesmo tempo, podemos ter um loop que reexibe constantemente o sinal selecionado, permitindo ao usuário pressionar um botão e ver o sinal selecionado aparecer no display de LED com muito pouca latência.

2. Queremos ser capazes de transmitir um sinal

Como existem dois botões, podemos designar um para seleção e outro para confirmação. Como o aplicativo do usuário, simplesmente enviamos o sinal pela rede como um número. Não há nenhuma outra informação necessária.

Falarei mais sobre o protocolo de sinal simples na próxima seção.

Etapa 2: O protocolo de sinal: uma linguagem simples para comunicação de rede

Os sinais a seguir podem ser considerados como o conjunto de todas as palavras possíveis que os dispositivos podem usar para falar uns com os outros. Como a rede é tão simples, não há muito a dizer e, portanto, podemos representar esses três sinais por valores inteiros simples.

0. Reiniciar

  • Identificador no código: SIG-R
  • Valor inteiro: 0
  • Objetivo: Instruir todos os dispositivos dentro do alcance para interromper o que estão fazendo e agir como se tivessem acabado de inicializar. Se esse sinal atingir todos os dispositivos da rede, toda a rede será reiniciada e os usuários poderão iniciar um novo jogo. Este sinal só pode ser transmitido por um dispositivo raiz.

1. Conversão A

  • Identificador no código: SIG-A
  • Valor inteiro: 1
  • Objetivo: Informar qualquer dispositivo que esteja no estado LISTEN_A, uma vez que receba o sinal de conversão, para mudar para o estado TEAM_A.

2. Conversão B

  1. Identificador no código: SIG-B
  2. Valor inteiro: 2
  3. Objetivo: Informar a qualquer dispositivo que esteja no estado LISTEN_B, assim que receber o sinal de conversão, para mudar para o estado TEAM_B.

Etapa 3: Queremos controlar as ações do dispositivo com base em seu estado atual

Queremos controlar as ações do dispositivo com base em seu estado atual
Queremos controlar as ações do dispositivo com base em seu estado atual
Queremos controlar as ações do dispositivo com base em seu estado atual
Queremos controlar as ações do dispositivo com base em seu estado atual
Queremos controlar as ações do dispositivo com base em seu estado atual
Queremos controlar as ações do dispositivo com base em seu estado atual

Por fim, podemos começar a escrever o código.

Primeiro, abra um novo projeto em Make Code

  • Crie uma nova função. Eu chamei o meu loop porque este é o loop principal do aplicativo
  • Adicione um bloco de loop que se repetirá indefinidamente. Usei while (true) porque um literal verdadeiro nunca será falso, portanto, o fluxo de controle do aplicativo nunca sairá do loop
  • Adicione blocos if-else suficientes para verificar se o dispositivo está em algum dos cinco estados possíveis
  • Crie uma variável para manter o estado atual do dispositivo
  • Crie variáveis para representar cada um dos cinco estados possíveis

    Observação: é normal que essas variáveis ainda não tenham nenhum valor atribuído. Nós vamos chegar a isso. Neste ponto, é mais importante que escrevamos um código limpo e fácil de ler

  • Altere cada condição nos blocos if-else para comparar o estado atual com um dos possíveis estados
  • Na parte inferior dos blocos if-else, adicione uma pausa por alguns milissegundos e crie uma variável para conter esse número. Iremos inicializá-lo mais tarde. Certifique-se de que a variável tenha um nome descritivo, como tick ou heartbeat. Como esse é o loop principal do dispositivo, essa pausa determinará a velocidade com que o dispositivo executa o loop principal, portanto, é um valor muito importante e muito importante para ser um número mágico sem nome.

Nota: Não se preocupe com os blocos cinza na terceira imagem. Eu vou chegar a isso mais tarde.

Etapa 4: Queremos reagir às contribuições do usuário

Queremos reagir às contribuições do usuário
Queremos reagir às contribuições do usuário
Queremos reagir às contribuições do usuário
Queremos reagir às contribuições do usuário

Agora, queremos dizer ao dispositivo como lidar com o pressionamento de botões. O primeiro pensamento pode ser simplesmente usar os blocos "Quando o botão é pressionado" na categoria de entrada, mas gostaríamos de um controle mais granular do que isso. Usaremos o bloco "no evento de (X) com valor (Y)" da categoria de controle na seção avançada, porque estamos avançados neste tutorial.

  • Crie quatro blocos "no evento de …".

    • Dois deles devem verificar a fonte do evento "MICROBIT_ID_BUTTON_A"
    • Dois deles devem verificar a fonte do evento "MICROBIT_ID_BUTTON_B"
    • Dos dois eventos direcionados a cada botão:

      • Deve-se verificar o evento do tipo "MICROBIT_BUTTON_EVT_UP"
      • Deve-se verificar o evento do tipo "MICROBIT_BUTTON_EVT_DOWN"
    • Nota: Essas opções em letras maiúsculas são rótulos usados no código micro: bit de nível inferior. Eles são simplesmente marcadores de posição que mais tarde são substituídos por inteiros quando o código é compilado para um binário executável. É mais fácil para humanos usar esses rótulos do que pesquisar qual número inteiro inserir, embora ambos funcionem da mesma maneira.
  • Eu escolhi, por uma questão de estilo, que cada bloco "on event from …" chame uma função que descreva o evento gerado. Embora não seja estritamente necessário, na minha opinião, isso melhora a legibilidade. Se alguém desejar fazer isso, eles podem colocar o código de manipulação de eventos dentro do próprio bloco "on event from …".

    Nota: O bloco de código que lida com a resposta do dispositivo a um evento é intuitivamente chamado de "manipulador de eventos"

  • Adicione, em cada manipulador de eventos, a mesma estrutura if-else usada para dividir o fluxo de controle com base no estado do dispositivo como a estrutura no loop de estado principal.
  • Adicione blocos de atribuição que modificam esse estado do dispositivo conforme especificado por nosso diagrama de estado

    • Sabemos que quando o dispositivo está no estado UNASSIGNED, o dispositivo deve reagir ao botão A pressionado por uma transição para o estado LISTEN_A, e ao botão B pressionado por uma transição para o estado LISTEN_B
    • Também sabemos que quando o dispositivo está no estado LISTEN_A ou LISTEN_B, o dispositivo deve reagir ao botão A liberado e ao botão B liberado, respectivamente, fazendo a transição de volta para o estado UNASSIGNED.
    • Finalmente, sabemos que quando o dispositivo está no estado TEAM_A ou TEAM_B, o dispositivo deve reagir ao botão A pressionado e ao botão B pressionado transmitindo SIG_A e transmitindo SIG_B respectivamente.

      Não é necessário, neste ponto, preencher os detalhes dos sinais de transmissão. Veremos isso mais tarde. O que é importante é que instruamos essas funções a usar o código que escreveremos, dando a esse bloco de ações um nome, como broadcastSignalSIG_A, que descreve o que deve ser feito naquele ponto

Etapa 5: Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado

Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado
Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado
Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado
Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado
Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado
Queremos inicializar os valores dos dados na memória do dispositivo quando o dispositivo for inicializado

Neste ponto, usamos muitas variáveis (nomes para dados), mas na verdade não atribuímos valores a esses nomes. Queremos que o dispositivo carregue os valores de todas essas variáveis na memória quando for inicializado, portanto, colocamos a inicialização para essas variáveis em um bloco "on start".

Estes são os valores que devemos inicializar:

  • Constantes de sinal, de acordo com o protocolo de sinal. Os valores DEVEM ser:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Nota: Prefixei essas constantes com "EnumSignals" para denotar que essas variáveis devem se comportar como se fizessem parte de um tipo enumerado chamado Signals. É assim que essas variáveis podem ser implementadas em outras linguagens de programação. A definição e explicação dos tipos enumerados estão além do escopo do meu tutorial. Pode-se pesquisar no Google, se assim o desejar. Esses prefixos são simplesmente escolhas estilísticas e não são essenciais para o funcionamento adequado do programa.
  • Constantes de estado, que podem ser arbitrárias, desde que tenham um valor. Fiz uma escolha de estilo para simplesmente usar inteiros ascendentes de 0, assim:

    • NÃO ATRIBUÍDO = 0
    • LISTEN_A = 1
    • LISTEN_B = 2
    • TEAM_A = 3
    • TEAM_B = 4
    • Observação: também tomei a mesma decisão de estilo em relação aos prefixos dessas variáveis. Além disso, mencionarei que tudo sobre essas atribuições, os valores e a ordem, é completamente arbitrário. Nem importa se esses valores são consistentes de dispositivo para dispositivo, porque eles são usados apenas internamente e não para comunicação pela rede. O que importa é que as variáveis tenham um valor e que possam ser comparadas entre si para ver se são equivalentes ou não.
  • Para facilitar a leitura, uma constante chamada BOOT_STATE e defina-a como UNASSIGNED. Isso torna o fato de redefinirmos para o estado de inicialização, em vez de um estado mais arbitrário, mais explícito quando o dispositivo recebe um sinal de reinicialização, que implementaremos mais tarde.
  • Constantes de animação, usadas na etapa a seguir para criar animações que permitem interrupção de latência extremamente baixa por meio da entrada do usuário. Não os usamos até agora, mas certamente serão explicados e usados na seção seguinte. O significado de alguns deles deve ser intuitivo devido aos seus nomes.

    • 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
  • Outra variável para animação, desta vez um contador que definitivamente não é constante. Como a maioria dos contadores, nós o inicializamos como 0

    iTickLoadingAnimation = 0

  • Crie duas séries de variáveis para conter quadros de animações. A primeira, que chamo de "animação de carregamento", deve ter quatro imagens (que você deve ter adivinhado pela última inicialização constante), e a segunda, que chamo de "animação transmitida", que deve ter três imagens. Eu recomendo nomear as variáveis para corresponder aos quadros da animação, por exemplo, ringAnimation0, ringAnimation1…

    Crie os mesmos valores de imagem que eu criei ou crie imagens mais originais e mais legais

  • Por último, mas não menos importante, devemos definir o grupo de rádio do dispositivo para 0 usando o bloco "grupo de conjunto de rádio (X)"
  • Opcionalmente, escreva a mensagem "Inicialização concluída" na saída serial para informar ao usuário que tudo correu bem.
  • Agora que configuramos o dispositivo, podemos chamar nossa função de loop de estado.

Etapa 6: Queremos exibir animações e gráficos usando o display LED 5 X 5

Queremos exibir animações e gráficos usando o display LED 5 X 5
Queremos exibir animações e gráficos usando o display LED 5 X 5
Queremos exibir animações e gráficos usando o display LED 5 X 5
Queremos exibir animações e gráficos usando o display LED 5 X 5
Queremos exibir animações e gráficos usando o display LED 5 X 5
Queremos exibir animações e gráficos usando o display LED 5 X 5

E agora para algo completamente diferente.

Queremos exibir algumas animações e alguns personagens, mas não queremos interromper o loop de estado principal. Infelizmente, os blocos que exibem imagens e strings de texto têm um atraso de 400 ms por padrão. Não há como mudar isso sem editar a representação javascript do código. Então, é isso que faremos.

  • Crie uma função para cada imagem. Isso permitirá que se use um único bloco para exibir a imagem em vez de editar o javascript todas as vezes. Neste programa específico, nenhuma imagem é usada mais de uma vez, mas ainda acho que esse estilo torna o código mais fácil de ler.
  • Adicione, em cada nova função, um bloco "mostrar imagem (X) no deslocamento 0" com o nome da variável de imagem correspondente substituindo (X)
  • Adicione, no loop de estado principal. "Mostrar blocos de string (X)" para cada bloco além daquele que trata do estado UNASSIGNED. Adicione um caractere para o dispositivo exibir para indicar seus diferentes estados. Aqui está o que eu fiz:

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

      Para o estado UNASSIGNED, faça uma chamada para uma função que atualizará a animação de carregamento. Preencheremos os detalhes desta função a seguir

  • Mude para o modo javascript.
  • Encontre todas as chamadas para X.showImage (0) e basic.showString (X)
  • Altere cada um para X.showImage (0, 0) ou basic.showString (X, 0)

    • Adicionar este argumento extra definirá o atraso após a ação em 0. Por padrão, isso é omitido e o dispositivo fará uma pausa de 400 ms após a execução de cada um desses blocos.
    • Agora, temos um mecanismo quase sem latência para exibir nossas imagens em nossos blocos de animação, que agora podemos construir

Primeiro, construiremos a função de animação broadcast relativamente simples. É mais simples porque não queremos que o usuário seja capaz de fazer nada até que a função seja concluída, para impedi-los de enviar spam para a função de transmissão. Para fazer isso, podemos simplesmente manter o fluxo de controle restrito ao bloco até que a função seja concluída, o que é um comportamento padrão.

  • Crie uma função que exibirá animação de transmissão.
  • Dentro desse bloco, adicione três chamadas de função, uma para cada quadro da animação, na ordem em que devem ser exibidas
  • Adicione um bloco "wait (us) (X)" após cada chamada para uma função de exibição de imagem.

    Nota: Este bloco, da seção de controle avançado, irá ainda mais longe do que "pausa (ms)", pois congelará completamente o processador até que o tempo especificado tenha decorrido. Quando o bloco de pausa é usado, é possível que o dispositivo execute outras tarefas nos bastidores. Isso é impossível com o bloco de espera

  • Substitua (X) por (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • A animação agora deve funcionar corretamente

Em segundo lugar, construiremos o mecanismo para exibir a animação de carregamento. A ideia por trás disso é atualizar o display de LED em um intervalo específico, que definimos na variável MS_PER_DEVICE_TICK. Este valor, o comprimento do tique do dispositivo, é o número de milissegundos que o dispositivo pausa após completar cada iteração do loop de estado. Como esse valor é pequeno o suficiente, podemos atualizar a exibição uma vez durante cada iteração do loop de exibição e parecerá ao usuário que a animação está progredindo perfeitamente e, quando o estado mudar, haverá muito pouca latência entre a entrada do usuário o display sendo atualizado. Contando tiques, o que fazemos com a variável iTickLoadingAnimation, podemos exibir o quadro apropriado da animação.

  • Crie uma função que irá atualizar a animação de carregamento
  • Adicione uma condição para verificar se o contador de tiques atingiu seu valor máximo. Esta condição será verdadeira se o valor do contador de tiques for maior que o número de quadros na animação de carregamento multiplicado pelo número de tiques para exibir cada quadro

    Se a condição for verdadeira, redefina o iTickLoadingAnimation para 0

  • Adicione um bloco de condições if-else. Isso determinará qual quadro da animação será exibido.

    Para cada quadro da animação, se o contador de tiques for menor que o número de tiques em cada animação multiplicado pelo número do quadro da animação (começando em 1), exiba esse quadro, caso contrário, verifique se o próximo quadro é aquele a Ser exibido

  • Na parte inferior do bloco, incremente o iTickLoadingAnimation
  • A animação agora deve funcionar corretamente

Nota: Todos os blocos cinzas que aparecem no meu exemplo são gerados quando se edita a representação javascript de um bloco. Significa simplesmente que o bloco representa o código javascript que não pode ser representado usando o conjunto padrão de blocos e deve ser editado na forma de texto.

Etapa 7: Queremos transmitir dados sem fio usando o rádio do dispositivo

Queremos transmitir dados sem fio usando o rádio do dispositivo
Queremos transmitir dados sem fio usando o rádio do dispositivo

Esta etapa é muito mais curta do que a anterior. Na verdade, é provavelmente a etapa mais curta em todo o tutorial.

Lembre-se de que, quando programamos a resposta do dispositivo à entrada do usuário, havia dois blocos na captura de tela que não foram explicados nessa seção. Eram chamadas para funções que enviam sinais pelo rádio. Mais especificamente:

  • No botão A pressionado:

    • Se o dispositivo estiver no estado TEAM_A:

      Sinal de transmissão SIG_A

  • No botão B pressionado:

    • Se o dispositivo estiver no estado TEAM_B

      Sinal de transmissão SIG_B

Crie essas funções se ainda não existirem.

Em cada função:

  • Chame a função de transmissão de animação. Isso impedirá que qualquer outra coisa aconteça até que seja concluído, o que será em MS_PER_FRAME_BROADCAST_ANIMATION * 3 = 1,5 segundos. A constante é multiplicada por três porque há três quadros na animação. Isso é arbitrário e mais pode ser adicionado se a atualização estética for grande o suficiente. Um segundo objetivo desta animação é evitar que um usuário envie spam para a função de transmissão.
  • Adicione um bloco "número de envio de rádio (X)", onde é a constante de sinal mencionada no nome da função

É tudo o que se precisa para transmitir pelo rádio.

Etapa 8: Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo

Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo
Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo
Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo
Queremos ouvir e receber dados pelo rádio do dispositivo e processá-los de acordo

Esta é a etapa final para criar o aplicativo principal.

Vamos dizer ao dispositivo como processar os sinais de rádio de entrada. Primeiro, nosso dispositivo nomeará o sinal recebido. Então, com base no valor desse sinal, ele decidirá qual ação tomar, se houver.

Primeiro:

  1. Crie um bloco de código começando com um bloco "no rádio recebido (X)".
  2. Opcionalmente, atribua esse valor recebido a outra variável com um nome mais descritivo.
  3. Chame uma função que irá processar o sinal

Em segundo lugar, na função de processamento de sinal:

  1. Crie um bloco de instruções if-else que ramificam o fluxo de controle com base no valor do sinal.
  2. Se o sinal fosse SIG_R

    Defina o estado do dispositivo para BOOT_STATE (é por isso que criamos essa constante anteriormente)

  3. Se o sinal era SIG_A e se o estado atual é LISTEN_A

    Defina o estado do dispositivo para TEAM_A

  4. Se o sinal era SIG_B e se o estado atual é LISTEN_B

    Defina o estado do dispositivo para TEAM_B

É isso. O aplicativo foi concluído.

Etapa 9: Dispositivo raiz: queremos ser capazes de selecionar um sinal

Dispositivo raiz: queremos ser capazes de selecionar um sinal
Dispositivo raiz: queremos ser capazes de selecionar um sinal

Agora, vamos escrever uma aplicação simples para um dispositivo "raiz", ou seja, um dispositivo que controlará a rede.

Este dispositivo precisará executar duas funções:

  • Queremos permitir que o usuário selecione um de nossos sinais
  • Queremos permitir que o usuário transmita o sinal

Como a especificação deste aplicativo é um subconjunto do anterior, darei uma visão geral, mas não entrarei em tantos detalhes como antes. A imagem acima contém o código completo para este aplicativo.

Para permitir que o usuário selecione um sinal:

  1. Inicialize 5 variáveis em um bloco "on start":

    1. Os três sinais (0, 1, 2)
    2. O número de sinais (3)
    3. Uma variável para manter o sinal atualmente selecionado (inicialmente definido para o primeiro sinal, 0)
  2. Lidar com o pressionamento do botão A:

    1. Incrementar o sinal selecionado
    2. Verifique se o sinal selecionado é maior ou igual ao número de sinais

      Em caso afirmativo, defina o sinal selecionado para 0

  3. Após o bloco inicial, execute um loop "para sempre" que exibe o valor do sinal selecionado atual sem atraso

Para permitir que o usuário transmita um sinal

  1. Defina o grupo de rádio para 0 no bloco "on start"
  2. Lidar com o pressionamento do botão B:

    Transmita o sinal selecionado usando um bloco "número de envio de rádio (X)"

É isso. O aplicativo do nó raiz é extremamente simples.

Etapa 10: Terminamos

Nós terminamos
Nós terminamos

Acima está uma foto dos dispositivos que executam o aplicativo. Os dois à direita estão executando o aplicativo "usuário" principal e o à esquerda está executando o aplicativo "root".

Eu demonstrei este jogo no CS Connections 2018, uma conferência de verão de uma semana para professores do ensino fundamental e médio sobre educação em ciência da computação. Distribuí cerca de 40 dispositivos aos professores e expliquei as regras. A maioria achou o jogo divertido e muitos o acharam confuso até descobrirem como jogar. A demonstração foi curta, mas achamos o jogo divertido entre um público bastante diversificado.

Mais informações sobre o CS Connections 2018 podem ser encontradas aqui.

Recomendado: