CryptoBotWars o Cómo construir demostraciones de mierda y por qué

¿Por qué mierda? Porque me gusta la autodesprecio y el juego no está cerca de la producción.

Fichas, robots, canales de pago y transmisiones en vivo

Así que creé CryptoBotWars, un juego en Raiden Network.

¿Quieres jugarlo? Sigue leyendo ...

Echa un vistazo al juego, detrás de escena o muestra de transmisión en vivo. ¡Y únete a nuestro chat de Riot!

¿Por qué? ... Tenía algunas preguntas:

  1. ¿Es fácil construir algo encima de Raiden en este momento? ¿Nos falta algo que sea bastante fácil de cambiar?
  2. ¿Cómo trabajaría Raiden en este momento para pagos uno a muchos y muchos a uno, casos frecuentemente relacionados con negocios?
  3. ¿La gente encontraría errores en Raiden? Los mejores probadores son los probadores despistados y recién incorporados.
  4. ¿Raiden se comportaría bien con un alto rendimiento?
  5. ¿Los pagos serían mediados con éxito (varias ubicaciones y configuraciones del sistema)

Un juego, especialmente combinado con cierto grado de entretenimiento, tiene el potencial de incentivar a nuevas personas a probar Raiden. Aún más, si agrega algunas recompensas en la parte superior.

Un juego ... o un servicio muy serio que aceptaría pagos fuera de la cadena , pero no tuve suficiente tiempo para este último, así que ahí tienes:

Dark Vader y Blue Yoda. Tazón de sopa y ping-pong Santa Hat! ¡Se ve muy bien! … Desde 4m de distancia

Esta publicación de blog está parcialmente dedicada al restaurante tailandés donde obtengo mi sopa de coco, tofu y verduras favorita de Berlín . Es por eso que siempre tenemos un montón de cuencos para llevar para hacer Vader Helmets & Santa Hats .

¿Cómo surgió la idea?

Un día, durante el almuerzo, estábamos discutiendo ideas para el taller de la Red Devcon4 Raiden, tratando de pensar en una aplicación divertida y simple que se pueda construir sobre Raiden. De alguna manera, llegamos a la conclusión de que un juego puede incentivar a más personas a probarlo.

Después lo pensé un poco más y decidí que un juego con un número ilimitado de usuarios podría mostrar mejor a Raiden, ya que probaría el rendimiento.

¿Pero qué juegos puedes jugar entre un número infinito de jugadores? Tal vez algo que requirió votar por un resultado.

Recordé el patrón del Dilema del Prisionero, donde dos jugadores intentan minimizar su pérdida sin poder comunicarse entre sí, pero no pueden encontrar una variante de juego adecuada para mi propósito.

Luego volví a la mesa de dibujo: votando por un resultado.

Entonces me di cuenta de que lo más simple que puedes hacer es piedra, papel o tijera. Dos jugadores, tres movimientos, cada usuario elige un jugador y un movimiento y la mayoría por jugador decide el movimiento final. Entonces el juego real se puede jugar entre los dos movimientos elegidos por la mayoría.

Eventualmente, el equipo exhibió una carrera divertida entre Deva y algunas personas conocidas en el espacio, combinando el taller introductorio con memes apropiados para Devcon y algo de emoción .

Pero, todavía quería construir mi demo de piedra, papel y tijera, ¡y ETHSingapur parecía un buen momento para hacerlo! (Dark Vader y Blue Yoda visitaron Singapur, pero no se incluyeron en la demostración, debido a otros problemas técnicos que tuve que resolver )

Los robots quieren criptografía

Tienes un juego, tienes Raiden, ¿por qué agregar otra variable a la ecuación?

Y los robots causan mucho dolor y no estoy hablando del Apocalipsis Robot. Aunque ya ves, me he estado preparando durante un tiempo para ser uno de los humanos tolerados: uRaiden Devcon3 Robo, los drones también quieren criptografía

  1. A mi compañero y a mí, que en realidad construimos el Devcon3 RC Car, realmente nos gustan los robots. Y él ya trajo un ejército de ellos a la casa ... es el más salvaje para las personas que no quieren crecer.
  2. Los robots son divertidos y lindos (¡uel vs. duelo de memes ahora!)
  3. Puse mi voz Yoda a trabajar! (el comienzo de otra carrera más ...)
  4. Pero en realidad los robots nos dan una idea de lo que podría ser el futuro .

¿Cómo empecé a construir?

~ 5,5 días fueron suficientes para hacer la configuración inicial y las conexiones del prototipo de robot para ETHSingapur.

Luego, durante las vacaciones de invierno, construí el juego actual sobre el primer prototipo.

Primero lo primero: probar el Robot SDK

Mi compañero ya sabía que Wonder Robots tenía un SDK de Python y probó algunos de los comandos. Este fue un buen momento para presentarle a Claudiu, un amigo nuestro, la programación. ¿Qué puede ser más divertido que programar robots? ¡Entonces lo hizo! Agregó comandos para el comportamiento de ganar / perder, junto con bandas sonoras personalizadas.

Flujo de juego

Ya había escrito algunas ideas de cómo podría ser el juego. Entonces, en lugar de crear realmente los diagramas lógicos del juego en este punto, salté a la fase de implementación. Esto resultó ser un mal movimiento, porque "me ayudó" a tomar algunas decisiones equivocadas debido a que no veía la imagen completa (estados de juego y UI refactorizados, lógica de servidor de juego defectuosa al calcular el resultado, este error de explotación.

Eventualmente arreglé las cosas más tarde y creé una mejor secuencia lógica:

Componentes finales

  1. Dark Vader RobotServer y Blue Yoda RobotServer
  2. GameGuardianServer
  3. GameGuardianRaidenNode
  4. Cliente del juego
  5. Transmisión en vivo en Twitch

2, 3, 4 están alojados en un VPS Digital Ocean.

Los servidores del robot están alojados en dos computadoras hogareñas.

Una de estas computadoras también transmite en vivo a través de la cámara web. Probamos muchas opciones de transmisión en vivo, desde las más populares hasta las autohospedadas, incluso buscando soluciones descentralizadas, pero todas tenían inconvenientes (latencia, resolución, identificación de transmisión dinámica, tiempo de configuración, etc.)

GameClient UI

De hecho, comencé con la interfaz de usuario primero.

Mi compañero sugirió usar el mismo control deslizante que ya tenía en Pipeline y mostrar cada estado del juego en una diapositiva individual. Pensé que esto era una buena idea. Se sentía como un libro de cuentos.

export const GameState = {
    nulo: 0, // No se está ejecutando el juego actual
    abierto: 1, // Durante el tiempo de juego, los usuarios pueden hacer movimientos
    cerrado: 2, // Durante el tiempo de resolución del juego, los usuarios esperan resultados y pagos
    resuelto: 3, // El juego y la resolución han terminado.
}

Puedes ver el código de vistas del estado del juego aquí.

GameGuardianServer

Después de tener una idea sobre los estados del juego, procedí a definir el juego y mover modelos, que corresponden a las colecciones de la base de datos MongoDB. Vea la versión actual aquí.

Luego agregué la API GameGuardian Raiden e implementé la lógica de resultados del juego, para calcular los ganadores, enviar los pagos fuera de la cadena y activar los movimientos del robot. Activado por el código? hacer un PR para mejorarlo!

mueve = espera moveController.find ({donde: {gameId: id}, orden: ["_id ASC"]});
raidenPayments = espera this.getRaidenPayments (TOKEN)
moves.forEach (sentMove => {
    Si (
        sentMove.amount &&
        sentMove.move &&
        sentMove.amount> = game.move_amount
    ) {
        raidenPayment = raidenPayments [0] .find ((pago) => {
            return payment.identifier === sentMove.paymentIdentifier;
        });
        if (raidenPayment) {
            total_amount + = sentMove.amount;
            move_count [sentMove.playerId] [sentMove.move] + = 1;
            validMoves.push (sentMove);
        }
    }
});

sorted_moves_1 = Object.entries (move_count ['1']). sort ((a: any, b: any) => {return a [1] - b [1]});
sorted_moves_2 = Object.entries (move_count ['2']). sort ((a: any, b: any) => {return a [1] - b [1]});
move1 = sorted_moves_1 [2] [1]> 0? sorted_moves_1 [2] [0]: nulo;
move2 = sorted_moves_2 [2] [1]> 0? sorted_moves_2 [2] [0]: RockPaperScissorsGetLoser [move1];
// Si tenemos un jugador, asegúrate de que gane
if (! move1) {
    move1 = RockPaperScissorsGetLoser [move2];
}
winnerMove = RockPaperScissorsGetLoser [move1] === move2? mover1: mover2;
validMoves.forEach ((move) => {
    // Recompensamos a ambos jugadores si sus movimientos finales son los mismos
    if (move.move === ganador de movimiento) {
        WinningMoves.push (movimiento);
    }
});
guardian_amount = total_amount / 10;
total_amount - = guardian_amount;
winner_amount = total_amount / winnerMoves.length;
gameUpdate = {
        WinningMove,
        jugador1:  {
            recuento: sorted_moves_1 [0] [1] + sorted_moves_1 [1] [1] + sorted_moves_1 [2] [1],
            mover: mover1,
            move_count: move_count ['1'],
        },
        player2:  {
            recuento: sorted_moves_2 [0] [1] + sorted_moves_2 [1] [1] + sorted_moves_2 [2] [1],
            mover: mover2,
            move_count: move_count ['2'],
        },
        cantidad: ganador_cantidad,
        amountGuardian: guardian_amount,
        jugadores: movimientos.longitud,
};

this.updateById (id, gameUpdate);
// Hacer pagos de Raiden a los ganadores
winnerMoves.forEach ((move) => {
    this.sendRaidenPayment (
        SIMBÓLICO,
        move.userAddress,
        ganador_cantidad,
        move.paymentIdentifier
    );
});
this.sendRobotCommands (move1, move2, winnerMove);

Gestión del tiempo: la clave del éxito

O el dolor de implementar temporizadores en el lado del cliente, que debe coincidir con el servidor.

El juego está cronometrado y los estados del juego también están cronometrados. Debido a que elegí tener un número infinito de usuarios simultáneos, tuve que limitar el soporte a un solo juego a la vez, para mantener el desarrollo simple.

Entonces, ¿quién comienza el juego?

Configurar un trabajo cron de servidor o similar para crear juegos de forma regular parecía ser el peor enfoque, ya que llenaría la base de datos de una manera inútil.

Opté por un cliente que inició el nuevo juego. En resumen, si no hay un juego actual en ejecución, el cliente crea uno. Si es así, los datos del juego se envían al cliente.

Los datos del juego también contienen startTime del juego, junto con gameTime (cuánto durará el estado abierto) y resolveTime (cuánto durará la resolución). El cliente usa estos valores para establecer los temporizadores aquí y aquí.

Los temporizadores se utilizan para activar algunas de las solicitudes al GameGuardianServer. Por ejemplo, cuando el estado de GameOpen ha finalizado, GameClient envía los datos de movimiento sin procesar. O cuando se alcanza el estado GameResolved, se envía una solicitud al servidor para resolver el estado del juego o devolver el estado de resolución si ya se resolvió, activando el GameGuardianServer para calcular los ganadores, enviar los pagos fuera de la cadena y activar los movimientos del robot .

Robots - toques finales

Los servidores del robot están alojados en dos computadoras hogareñas. ¿Por qué dos? Porque ambos robots Dash & Cue usan Bluetooth para conectarse a la computadora. El SDK actual primero desconecta todos los dispositivos conectados y luego conecta el robot apropiado.

Cada robot tiene múltiples rutas para: conectarse al robot, configurar la apariencia, mover comandos de voz, ganar / perder comandos. Opté por usar Gunicorn, porque necesitamos mantener vivo el proceso de conexión en todos los comandos.

Tenga en cuenta que transmitimos en vivo los robots de vez en cuando y esto ha transformado nuestra casa en un extraño estudio de mimo.

La conexión a Internet y el enrutador doméstico no han facilitado el trabajo.

Conclusiones

Despertó tu interés? Prueba el juego: https://cryptoplayer.one

¡Chatee con nosotros para dar su opinión o solicite ayuda para configurar sus canales Raiden o envíenos un mensaje para despertar a los robots! Chat antidisturbios

Parte 2 próximamente con más conclusiones y trucos de robots ... ¡pero necesito ver algunos aplausos aquí!

Leer: CryptoBotWars - Parte 2: Conclusiones