Tabla de contenido:

Network Rivalry: un juego de baja latencia para BBC Micro: bit: 10 pasos (con imágenes)
Network Rivalry: un juego de baja latencia para BBC Micro: bit: 10 pasos (con imágenes)

Video: Network Rivalry: un juego de baja latencia para BBC Micro: bit: 10 pasos (con imágenes)

Video: Network Rivalry: un juego de baja latencia para BBC Micro: bit: 10 pasos (con imágenes)
Video: [BRAZIL] 20 OCT. | Directo | enlightED Hybrid Edition 2021 2024, Mes de julio
Anonim
Network Rivalry: un juego de baja latencia para BBC Micro: bit
Network Rivalry: un juego de baja latencia para BBC Micro: bit
Network Rivalry: un juego de baja latencia para BBC Micro: bit
Network Rivalry: un juego de baja latencia para BBC Micro: bit

En este tutorial, explicaré cómo implementar un juego multijugador básico en BBC micro: bit con las siguientes características:

  • Una interfaz sencilla
  • Baja latencia entre las pulsaciones de botones y las actualizaciones de pantalla
  • Un número flexible de participantes
  • Fácil control del juego mediante un dispositivo remoto maestro ("raíz")

El juego es esencialmente una simulación de política. Todos los jugadores comienzan sin estar asignados a ningún equipo, excepto dos jugadores. Uno de estos jugadores está asignado al Equipo A y el otro al Equipo B.

El objetivo del juego es que cada jugador esté en el equipo con la mayoría de los jugadores en el momento en que todos se conviertan.

El diagrama anterior ilustra una máquina de estados finitos, es decir, una especificación de los estados en los que puede estar el dispositivo y las transiciones entre esos estados.

Se puede pensar en un estado como el conjunto actual de datos que describe la memoria del dispositivo desde que se encendió. Según esos datos, el dispositivo puede realizar ciertas acciones o reaccionar de manera diferente a la entrada del usuario.

Una transición es una condición lógica que, cuando es verdadera, hace que el dispositivo cambie de estado. Una transición puede ser de un estado a otro. Un estado puede tener múltiples transiciones.

El diagrama anterior especifica los siguientes estados:

  • Sin asignar
  • Escuche A
  • Escuche B
  • Equipo A
  • Equipo B

Un dispositivo que ejecuta el código del juego puede estar en cualquiera de estos cinco estados, pero solo uno a la vez, y solo estos cinco.

Asumiré a lo largo de la guía que está utilizando el editor MakeCode de Microsoft, que se puede encontrar en:

La implementación completa del juego se puede encontrar aquí:

makecode.microbit.org/_CvRMtheLbRR3 ("microbit-demo-user" es el nombre del proyecto)

Y la implementación del controlador de red maestro ("raíz") se puede encontrar aquí:

makecode.microbit.org/_1kKE6TRc9TgE ("microbit-demo-root" es el nombre del proyecto)

Me referiré a estos ejemplos a lo largo de mi tutorial.

Paso 1: Consideraciones de diseño de imagen grande

Antes de escribir cualquier código, debemos pensar en cómo queremos que se vea nuestro producto final. en otras palabras, ¿cuáles son los requisitos de la aplicación? ¿Qué debería decirle nuestro código al dispositivo cuando esté terminado? He dividido la funcionalidad de la aplicación principal en seis categorías, cada una de las cuales puede considerarse desde una perspectiva de diseño diferente.

  1. Queremos controlar las acciones del dispositivo en función de su estado actual.
  2. Queremos que el dispositivo reaccione a la entrada del usuario.
  3. Es posible que deseemos mostrar animaciones y gráficos utilizando la pantalla LED de 5 x 5
  4. Queremos inicializar los valores de los datos en la memoria del dispositivo cuando el dispositivo se inicia.
  5. Queremos transmitir datos de forma inalámbrica utilizando la radio del dispositivo.
  6. Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia.

Permítanme entrar en un poco más de detalle sobre cada uno.

1. Queremos controlar las acciones del dispositivo en función de su estado actual

Como la mayoría de los otros programas, la ejecución de las instrucciones especificadas por el código ocurre una línea a la vez. Queremos que nuestro dispositivo ejecute ciertas instrucciones basadas en su estado interno, como se ilustra en el diagrama en la parte superior de este tutorial. Podríamos escribir una serie de condicionales después de cada bloque de código que verifique que el dispositivo debería estar haciendo, pero este enfoque puede volverse muy complicado muy rápidamente, por lo que usaremos un bucle infinito que simplemente verifica una variable y se basa en esa variable, ejecuta un conjunto específico de instrucciones o no hace nada en absoluto. Esta variable se identificará con el sufijo "_state" tanto en nuestra aplicación de usuario como en nuestra aplicación raíz.

2. Queremos que el dispositivo reaccione a la entrada del usuario

A pesar de que la ejecución normal del código ocurre secuencialmente, es decir, una línea a la vez, necesitamos que nuestro dispositivo reaccione a las pulsaciones de botones mientras el bucle de estado principal determina qué debe hacer el dispositivo en un momento dado. Para ese propósito, el dispositivo tiene la capacidad de enviar señales al software de nivel inferior que interactúa con el hardware, lo que desencadena lo que se llama un evento. Podemos escribir código que le indique al dispositivo que haga algo cuando detecte un tipo específico de evento.

3. Queremos mostrar animaciones y gráficos utilizando la pantalla LED de 5 x 5

El mecanismo para hacer esto parece ser simple, pero el bloque que muestra una imagen agrega un retraso oculto de 400 ms. Debido a que queremos que nuestro dispositivo continúe ejecutando su ciclo de estado con la menor latencia posible, necesitaremos editar el código javascript para minimizar el retraso.

4. Queremos inicializar los valores de los datos en la memoria del dispositivo cuando el dispositivo se inicia

Antes de que nuestro dispositivo haga algo, la aplicación necesita cargar sus datos en la memoria. Esto incluye variables constantes nombradas para la legibilidad del código, variables que contienen imágenes, que pueden ser parte de una animación, y variables de contador que deben comenzar en 0 para funcionar correctamente. Terminaremos con una larga lista de nombres de variables y sus valores recién asignados. Como elección de estilo personal, denotaré valores constantes, es decir, valores que nunca necesitaré cambiar, usando ALL_CAPS. También prefijaré identificadores de variables principales con un nombre de categoría que se refiera a un tipo de objeto o tipo al que pertenece el identificador. Esto es en un intento de hacer que el código sea más fácil de seguir. Nunca usaré un nombre de variable como "elemento" o "x" debido a la ambigüedad que surge al intentar descifrar el código.

5. Queremos transmitir datos de forma inalámbrica mediante la radio del dispositivo

En realidad, esta es una tarea bastante simple cuando se usa el lenguaje de bloques MakeCode. Simplemente configuramos todos los dispositivos en el mismo grupo de radio en el momento del arranque y luego, cuando queremos enviar una señal, podemos pasar un solo número al bloque "Número de envío de radio" que se nos proporciona. Es importante que el remitente y el receptor estén trabajando en el mismo grupo de radio, porque si no, estarán enviando o recibiendo en diferentes frecuencias y la comunicación no será exitosa.

6. Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia

Teniendo en cuenta las mismas consideraciones que el elemento anterior, escucharemos las transmisiones entrantes de la misma manera que escucharemos la entrada del usuario: con un controlador de eventos. Escribiremos un bloque de código que examinará las señales entrantes y comprobará si se debe realizar alguna acción sin perturbar el bucle de estado principal.

Además, debemos considerar brevemente el diseño de la aplicación raíz mucho más simple, un programa que permitirá que un dispositivo controle toda la red. No dedicaré mucho tiempo a esto, ya que es mucho más simple que el diseño anterior y gran parte es simplemente repetición. He dividido la funcionalidad del dispositivo raíz en tres categorías.

  1. Queremos poder seleccionar una señal
  2. Queremos poder transmitir una señal

-

1. Queremos poder seleccionar una señal

Esto se puede hacer simplemente haciendo que un botón recorra las posibles señales. Dado que solo hay tres, este enfoque será suficiente. Al mismo tiempo, podemos tener un bucle que constantemente vuelve a mostrar la señal seleccionada, permitiendo al usuario presionar un botón y ver la señal seleccionada aparecer en la pantalla LED con muy poca latencia.

2. Queremos poder transmitir una señal

Dado que hay dos botones, podemos designar uno para la selección y el otro para la confirmación. Al igual que la aplicación de usuario, simplemente enviamos la señal a través de la red como un número. No se requiere ninguna otra información.

Hablaré más sobre el protocolo de señal simple en la siguiente sección.

Paso 2: Protocolo de señales: un lenguaje sencillo para la comunicación en red

Las siguientes señales se pueden considerar como el conjunto de todas las palabras posibles que los dispositivos pueden usar para comunicarse entre sí. Debido a que la red es tan simple, no hay mucho que decir, por lo que podemos representar estas tres señales mediante valores enteros simples.

0. Restablecer

  • Identificador en el código: SIG-R
  • Valor entero: 0
  • Propósito: Dígale a todos los dispositivos dentro del alcance que dejen de hacer lo que están haciendo y actúen como si acabaran de arrancar. Si esta señal llega a todos los dispositivos de la red, toda la red se reiniciará y los usuarios podrán iniciar un nuevo juego. Esta señal solo puede ser transmitida por un dispositivo raíz.

1. Conversión A

  • Identificador en el código: SIG-A
  • Valor entero: 1
  • Propósito: decirle a cualquier dispositivo que esté en el estado LISTEN_A, una vez que reciba la señal de conversión, que cambie al estado TEAM_A.

2. Conversión B

  1. Identificador en el código: SIG-B
  2. Valor entero: 2
  3. Propósito: decirle a cualquier dispositivo que esté en el estado LISTEN_B, una vez que reciba la señal de conversión, que cambie al estado TEAM_B.

Paso 3: queremos controlar las acciones del dispositivo en función de su estado actual

Queremos controlar las acciones del dispositivo en función de su estado actual
Queremos controlar las acciones del dispositivo en función de su estado actual
Queremos controlar las acciones del dispositivo en función de su estado actual
Queremos controlar las acciones del dispositivo en función de su estado actual
Queremos controlar las acciones del dispositivo en función de su estado actual
Queremos controlar las acciones del dispositivo en función de su estado actual

Por fin, podemos empezar a escribir código.

Primero, abra un nuevo proyecto en Make Code

  • Crea una nueva función. Llamé al ciclo mío porque este es el ciclo central de la aplicación.
  • Agregue un bloque de bucle que se repetirá indefinidamente. Usé while (verdadero) porque un verdadero literal nunca será falso, por lo tanto, el flujo de control de la aplicación nunca saldrá del ciclo
  • Agregue suficientes bloques if-else para verificar si el dispositivo se encuentra en alguno de sus cinco estados posibles
  • Crea una variable para mantener el estado actual del dispositivo
  • Cree variables para representar cada uno de los cinco estados posibles

    Nota: Está bien que estas variables aún no tengan ningún valor asignado. Llegaremos a eso. En este punto, es más importante que escribamos código limpio y fácil de leer

  • Cambie cada condición en los bloques if-else para comparar el estado actual con uno de los estados posibles
  • En la parte inferior de los bloques if-else, agregue una pausa durante algunos milisegundos y cree una variable para contener ese número. Lo inicializaremos más tarde. Asegúrese de que la variable tenga un nombre descriptivo, como tic o latido. Debido a que este es el bucle central del dispositivo, esta pausa determinará la velocidad a la que el dispositivo ejecuta el bucle principal, por lo que es un valor muy importante y es demasiado importante para ser un número mágico sin nombre.

Nota: No se preocupe por los bloques grises en la tercera imagen. Llegaré a esos más tarde.

Paso 4: queremos reaccionar a la entrada del usuario

Queremos reaccionar a la entrada del usuario
Queremos reaccionar a la entrada del usuario
Queremos reaccionar a la entrada del usuario
Queremos reaccionar a la entrada del usuario

Ahora, queremos decirle al dispositivo cómo manejar las pulsaciones de botones. El primer pensamiento podría ser simplemente usar los bloques "Cuando se presiona el botón" en la categoría de entrada, pero nos gustaría un control más granular que eso. Usaremos el bloque "on event from (X) with value (Y)" de la categoría de control en la sección avanzada, porque estamos avanzados en este tutorial.

  • Cree cuatro bloques "en evento de …".

    • Dos de estos deben verificar la fuente del evento "MICROBIT_ID_BUTTON_A"
    • Dos de estos deben verificar la fuente del evento "MICROBIT_ID_BUTTON_B"
    • De los dos eventos dirigidos a cada botón:

      • Se debe verificar el evento de tipo "MICROBIT_BUTTON_EVT_UP"
      • Se debe verificar el evento de tipo "MICROBIT_BUTTON_EVT_DOWN"
    • Nota: Estas opciones en letras mayúsculas son etiquetas que se utilizan en el código micro: bit de nivel inferior. Son simplemente marcadores de posición que luego se reemplazan por números enteros cuando el código se compila en un binario ejecutable. Es más fácil para los humanos usar estas etiquetas que buscar qué entero poner, aunque ambas funcionarían de la misma manera.
  • Elegí, por cuestión de estilo, que cada bloque "on event from …" llame a una función que describa el evento generado. Aunque no es estrictamente necesario, en mi opinión esto mejora la legibilidad. Si uno desea hacerlo, puede poner el código de manejo de eventos dentro del bloque "on event from …".

    Nota: El bloque de código que maneja la respuesta del dispositivo a un evento se denomina intuitivamente "controlador de eventos"

  • Agregue, en cada controlador de eventos, la misma estructura if-else utilizada para dividir el flujo de control según el estado del dispositivo como la estructura en el bucle de estado principal.
  • Agregue bloques de asignación que modifiquen ese estado del dispositivo según lo especificado por nuestro diagrama de estado

    • Sabemos que cuando el dispositivo está en el estado NO ASIGNADO, el dispositivo debe reaccionar al botón A presionado por una transición al estado LISTEN_A, y al botón B presionado por una transición al estado LISTEN_B
    • También sabemos que cuando el dispositivo está en el estado LISTEN_A o LISTEN_B, el dispositivo debe reaccionar al botón A liberado y al botón B liberado, respectivamente, volviendo al estado SIN ASIGNAR.
    • Finalmente, sabemos que cuando el dispositivo está en estado TEAM_A o TEAM_B, el dispositivo debe reaccionar al botón A presionado y al botón B presionado transmitiendo SIG_A y transmitiendo SIG_B respectivamente.

      En este momento, no es necesario completar los detalles de las señales de transmisión. Llegaremos a eso más tarde. Lo importante es que le indiquemos a estas funciones que usen el código que escribiremos dándole un nombre a ese bloque de acciones, como broadcastSignalSIG_A, que describe lo que se debe hacer en ese punto

Paso 5: Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia

Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia
Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia
Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia
Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia
Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia
Queremos inicializar los valores de datos en la memoria del dispositivo cuando el dispositivo se inicia

En este punto, hemos utilizado muchas variables (nombres de datos), pero en realidad no hemos asignado valores a esos nombres. Queremos que el dispositivo cargue los valores de todas estas variables en la memoria cuando arranca, por lo que colocamos la inicialización de estas variables en un bloque "al inicio".

Estos son los valores que debemos inicializar:

  • Constantes de señal, según el protocolo de señal. Los valores DEBEN ser:

    • SIG_R = 0
    • SIG_A = 1
    • SIG_B = 2
    • Nota: prefijé estas constantes con "EnumSignals" para indicar que estas variables deben comportarse como si fueran parte de un tipo enumerado llamado Signals. Así es como se pueden implementar estas variables en otros lenguajes de programación. La definición y explicación de los tipos enumerados está más allá del alcance de mi tutorial. Uno puede buscarlo en Google si así lo desea. Estos prefijos son simplemente opciones de estilo y no son en absoluto esenciales para el correcto funcionamiento del programa.
  • Constantes de estado, que pueden ser arbitrarias siempre que tengan un valor. Hice una elección de estilo para usar simplemente números enteros ascendentes desde 0, así:

    • SIN ASIGNAR = 0
    • ESCUCHAR_A = 1
    • ESCUCHAR_B = 2
    • EQUIPO_A = 3
    • EQUIPO_B = 4
    • Nota: también tomé la misma decisión de estilo con respecto a los prefijos para estas variables. Además, mencionaré que todo sobre estas asignaciones, los valores y el orden, es completamente arbitrario. Ni siquiera importa que estos valores sean consistentes de un dispositivo a otro, porque solo se usan internamente y no para la comunicación a través de la red. Lo único que importa es que las variables tengan un valor y que se puedan comparar entre sí para ver si son equivalentes o no.
  • Para facilitar la lectura, una constante llamada BOOT_STATE y configúrela en UNASSIGNED. Esto hace que el hecho de que reiniciemos al estado de arranque, en lugar de un estado más arbitrario, sea más explícito cuando el dispositivo recibe una señal de reinicio, que implementaremos más adelante.
  • Constantes de animación, utilizadas en el siguiente paso para crear animaciones que permiten una interrupción de latencia extremadamente baja a través de la entrada del usuario. No los hemos utilizado hasta ahora, pero sin duda se explicarán y utilizarán en la siguiente sección. El significado de algunos de estos debe ser intuitivo debido a sus nombres.

    • 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
  • Otra variable para la animación, esta vez un contador que definitivamente no es constante. Como la mayoría de los contadores, lo inicializamos a 0

    iTickLoadingAnimation = 0

  • Crea dos series de variables para contener cuadros de animaciones. La primera, que llamo "animación de carga", debería tener cuatro imágenes (que puede haber adivinado por la última inicialización constante), y la segunda, que llamo "animación de transmisión", que debería tener tres imágenes. Recomiendo nombrar las variables para que se correspondan con los fotogramas de la animación, p. Ej. ringAnimation0, ringAnimation1…

    Cree los mismos valores de imagen que hice yo o cree imágenes más originales y geniales

  • Por último, pero no menos importante, debemos configurar el grupo de radio del dispositivo en 0 usando el bloque "grupo de radio set (X)"
  • Opcionalmente, escriba el mensaje "Inicialización completa" en la salida en serie para decirle al usuario que todo salió a la perfección.
  • Ahora que hemos terminado de configurar el dispositivo, podemos llamar a nuestra función de bucle de estado.

Paso 6: Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5

Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5
Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5
Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5
Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5
Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5
Queremos mostrar animaciones y gráficos con la pantalla LED de 5 x 5

Y ahora para algo completamente diferente.

Queremos mostrar algunas animaciones y algunos caracteres, pero no queremos interrumpir el ciclo de estado principal. Desafortunadamente, los bloques que muestran imágenes y cadenas de texto tienen un retraso de 400 ms por defecto. No hay forma de cambiar esto sin editar la representación javascript del código. Entonces, esto es lo que haremos.

  • Crea una función para cada imagen. Esto permitirá que uno use un solo bloque para mostrar la imagen en lugar de editar javascript cada vez. En este programa específico, ninguna imagen se usa más de una vez, pero sigo pensando que este estilo hace que el código sea más fácil de leer.
  • Agregue, en cada nueva función, un bloque "mostrar imagen (X) en el desplazamiento 0" con el nombre de la variable de imagen correspondiente reemplazando (X)
  • Agregue, en el bucle de estado principal. "Mostrar bloques de cadena (X)" en cada bloque además del que maneja el estado NO ASIGNADO. Agregue un carácter para que el dispositivo lo muestre para indicar sus diferentes estados. Aquí esta lo que hice:

    • ESCUCHAR_A: 'a'
    • ESCUCHAR_B: 'b'
    • EQUIPO_A: 'A'
    • EQUIPO_B: 'B'

      Para el estado NO ASIGNADO, realice una llamada a una función que actualizará la animación de carga. Completaremos los detalles de esta función a continuación

  • Cambie al modo javascript.
  • Encuentra todas las llamadas a X.showImage (0) y basic.showString (X)
  • Cambie cada uno de ellos a X.showImage (0, 0) o basic.showString (X, 0)

    • Al agregar este argumento adicional, el retraso después de la acción se establecerá en 0. De forma predeterminada, esto se omite y el dispositivo se detendrá durante 400 ms después de la ejecución de cada uno de estos bloques.
    • Ahora, tenemos un mecanismo casi libre de latencia para mostrar nuestras imágenes en nuestros bloques de animación, que ahora podemos construir.

Primero, crearemos la función de animación de transmisión relativamente simple. Es más simple porque no queremos que el usuario pueda hacer nada hasta que la función esté completa, para evitar que envíen spam a la función de transmisión. Para lograr esto, simplemente podemos mantener el flujo de control restringido al bloque hasta que se complete la función, que es el comportamiento estándar.

  • Cree una función que muestre la animación de transmisión.
  • Dentro de ese bloque, agregue tres llamadas de función, una para cada fotograma de la animación, en el orden en que deben mostrarse.
  • Agregue un bloque "wait (us) (X)" después de cada llamada a una función de visualización de imágenes.

    Nota: Este bloque, de la sección de control avanzado, irá incluso más lejos que "pausa (ms)" en el sentido de que congelará completamente el procesador hasta que haya transcurrido el tiempo especificado. Cuando se usa el bloque de pausa, es posible que el dispositivo realice otras tareas detrás de escena. Esto es imposible con el bloque de espera

  • Reemplaza (X) con (MS_PER_FRAME_BROADCAST_ANIMATION x MICROSECONDS_PER_MILLISECOND)
  • La animación ahora debería funcionar correctamente

En segundo lugar, crearemos el mecanismo para mostrar la animación de carga. La idea detrás de esto es actualizar la pantalla LED en un intervalo específico, que definimos en la variable MS_PER_DEVICE_TICK. Este valor, la longitud del tick del dispositivo, es el número de milisegundos que el dispositivo hace una pausa después de completar cada iteración del ciclo de estado. Debido a que este valor es lo suficientemente pequeño, podemos actualizar la pantalla una vez durante cada iteración del ciclo de visualización y le parecerá al usuario que la animación progresa sin problemas, y cuando el estado cambia, habrá muy poca latencia entre la entrada del usuario. la pantalla se actualiza. Contando tics, lo que hacemos con la variable iTickLoadingAnimation, podemos mostrar el cuadro apropiado de la animación.

  • Crea una función que actualizará la animación de carga.
  • Agregue una condición para verificar si el contador de ticks ha alcanzado su valor máximo. Esta condición será verdadera si el valor del contador de ticks es mayor que el número de fotogramas en la animación de carga multiplicado por el número de ticks para mostrar cada fotograma.

    Si la condición es verdadera, restablezca iTickLoadingAnimation a 0

  • Agregue un bloque de condiciones if-else. Estos determinarán qué fotograma de la animación mostrar.

    Para cada fotograma de la animación, si el contador de ticks es menor que el número de ticks en cada animación multiplicado por el número de fotograma de la animación (comenzando en 1), entonces muestre ese fotograma, de lo contrario verifique si el siguiente fotograma es el que debe se mostrará

  • En la parte inferior del bloque, incremente iTickLoadingAnimation
  • La animación ahora debería funcionar correctamente

Nota: Todos los bloques grises que aparecen en mi ejemplo se generan cuando se edita la representación javascript de un bloque. Simplemente significa que el bloque representa código javascript que no se puede representar con el conjunto estándar de bloques y debe editarse en forma de texto.

Paso 7: queremos transmitir datos de forma inalámbrica mediante la radio del dispositivo

Queremos transmitir datos de forma inalámbrica mediante la radio del dispositivo
Queremos transmitir datos de forma inalámbrica mediante la radio del dispositivo

Este paso es mucho más corto que el anterior. De hecho, probablemente sea el paso más corto de todo este tutorial.

Recuerde que cuando programamos la respuesta del dispositivo a la entrada del usuario, tenía dos bloques en la captura de pantalla que no se explicaron en esa sección. Eran llamadas a funciones que envían señales por radio. Más específicamente:

  • En el botón A presionado:

    • Si el dispositivo está en estado TEAM_A:

      Señal de transmisión SIG_A

  • En el botón B presionado:

    • Si el dispositivo está en estado TEAM_B

      Señal de transmisión SIG_B

Cree estas funciones si aún no existen.

En cada función:

  • Llame a la función de animación de transmisión. Esto evitará que suceda cualquier otra cosa hasta que se complete, que estará en MS_PER_FRAME_BROADCAST_ANIMATION * 3 = 1,5 segundos. La constante se multiplica por tres porque hay tres fotogramas en la animación. Esto es arbitrario y se pueden agregar más si la mejora estética es lo suficientemente grande. Un segundo propósito de esta animación es evitar que un usuario envíe spam a la función de transmisión.
  • Agregue un bloque "número de envío de radio (X)", donde es la constante de señal mencionada en el nombre de la función

Eso es todo lo que uno necesita transmitir por radio.

Paso 8: Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia

Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia
Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia
Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia
Queremos escuchar y recibir datos a través de la radio del dispositivo y procesarlos en consecuencia

Este es el paso final para crear la aplicación principal.

Vamos a decirle al dispositivo cómo procesar las señales de radio entrantes. Primero, nuestro dispositivo nombrará la señal recibida. Luego, basándose en el valor de esa señal, decidirá qué acción tomar, si corresponde.

Primero:

  1. Cree un bloque de código que comience con un bloque "en la radio recibida (X)".
  2. Opcionalmente, asigne ese valor recibido a otra variable con un nombre más descriptivo.
  3. Llame a una función que procesará la señal

En segundo lugar, en la función de procesamiento de señales:

  1. Cree un bloque de declaraciones if-else que ramifiquen el flujo de control en función del valor de la señal.
  2. Si la señal fuera SIG_R

    Establezca el estado del dispositivo en BOOT_STATE (es por eso que creamos esta constante antes)

  3. Si la señal fue SIG_A y si el estado actual es LISTEN_A

    Establece el estado del dispositivo en TEAM_A

  4. Si la señal fue SIG_B y si el estado actual es LISTEN_B

    Establece el estado del dispositivo en TEAM_B

Eso es todo. La aplicación está terminada.

Paso 9: Dispositivo raíz: queremos poder seleccionar una señal

Dispositivo raíz: queremos poder seleccionar una señal
Dispositivo raíz: queremos poder seleccionar una señal

Ahora escribiremos una aplicación sencilla para un dispositivo "root", es decir, un dispositivo que controlará la red.

Este dispositivo deberá realizar dos funciones:

  • Queremos permitir que el usuario seleccione una de nuestras señales.
  • Queremos permitir que el usuario transmita la señal.

Debido a que la especificación de esta aplicación es un subconjunto de la anterior, daré una descripción general, pero no entraré en tantos detalles como antes. La imagen de arriba contiene el código completo para esta aplicación.

Para permitir que el usuario seleccione una señal:

  1. Inicialice 5 variables en un bloque "al inicio":

    1. Las tres señales (0, 1, 2)
    2. El número de señales (3)
    3. Una variable para contener la señal seleccionada actualmente (inicialmente establecida en la primera señal, 0)
  2. Maneje presionando el botón A:

    1. Incrementar la señal seleccionada
    2. Compruebe si la señal seleccionada es mayor o igual al número de señales

      Si es así, establezca la señal seleccionada en 0

  3. Después del bloque de inicio, ejecute un bucle "para siempre" que muestre el valor de la señal seleccionada actual sin demora

Permitir al usuario transmitir una señal

  1. Establezca el grupo de radio en 0 en el bloque "al iniciar"
  2. Maneje una pulsación del botón B:

    Transmita la señal seleccionada utilizando un bloque "número de envío de radio (X)"

Eso es todo. La aplicación del nodo raíz es extremadamente simple.

Paso 10: Terminamos

Terminamos
Terminamos

Arriba hay una imagen de los dispositivos que ejecutan la aplicación. Los dos de la derecha ejecutan la aplicación principal de "usuario" y el de la izquierda ejecuta la aplicación "raíz".

Hice una demostración de este juego en CS Connections 2018, una conferencia de verano de una semana de duración para profesores de secundaria y preparatoria sobre educación en ciencias de la computación. Entregué unos 40 dispositivos a los profesores y les expliqué las reglas. La mayoría encontró el juego entretenido, y muchos lo encontraron confuso hasta que descubrieron cómo jugar. La demostración fue corta, pero nos pareció que el juego era divertido entre una multitud bastante diversa.

Puede encontrar más información sobre CS Connections 2018 aquí.

Recomendado: