Hidden People Blog

Devlog #8: Charla con el Grant Support squad respecto a 2dcl - Carga de escenas, nuevos personajes y mini mapa para Woods Folk (Antes Weekends in the Woods) - Cuentitos v0.2 - Reorganización en Laidaxai

2dcl

Tengo que reconocer que en el post anterior les mentí sin querer.

Dije que al otro día íbamos a empezar a trabajar en 2dcl, y si bien eso fue cierto y estuve trabajando en el login con Metamask, en la charla con Pablo del Grant Support Squad acordamos empezar el proyecto el 1ro de Agosto por el tema de los contratos.

Login con MetaMask

Hice un poco de progreso en esto entre el miércoles y el jueves antes de decidir esperar al 1ro.

Tengo un Pull Request abierto al respecto.

Ya logré implementar el workflow en un archivo de ejemplo (desacoplado del cliente).

Lo que hacemos es bastante simple aunque engorroso:

  1. Creamos un servidor web local
  2. Servimos una dapp pequeña con un botón de 'Conectarse con MetaMask'.
  3. Se hace el login y se guarda la dirección de Ethereum que se usó para conectarse.

Con esto alcanza dentro del cliente para poder cargar el avatar sin tener que editar los archivos de configuración. Lo primero que vamos a hacer a partir del 1ro de Agosto es integrar este pequeño workflow de login con nuestro cliente 2dcl.

Login with Metamask

Deployment con MetaMask

Pude también avanzar un poco con el workflow de deployment.

También tengo un Pull Request (pero en draft).

Todavía no llegué a poder subir los archivos, pero hay bastante progreso, pude entender leyendo el CLI de la fundación que se valida con una firma sobre el id de la entidad, así que implementé eso usando de base lo que había hecho para el login.

Agradecimiento

Quería agradecer especialmente a todo el equipo del Protocol Squad, producto de este grant. El trabajo que están haciendo no sólo de documentación sino con las implementaciones de referencia es fantástico.

El hecho de que una de las implementaciones de referencia use Rust, y en particular Bevy, es de gran ayuda para un proyecto como el nuestro.

La falta de esta documentación es lo que hizo que en nuestro grant anterior tuviésemos que cancelar una parte importante que era la de transformar las escenas 3d en 2d automáticamente. El trabajo del Protocol Squad va a habilitar este feature cuando el ECS7 tenga mayor penetración en las escenas de Decentraland. ¡¡¡Gracias!!!

Woods Folk (antes Weekends in the Woods)

Después de experimentar con varios logos y no encontrarle mucho el gusto al nombre Weekends in the Woods, decidimos renombrar el juego a Woods Folk, no está claro que quede ese nombre (Otra opción es Woodsfolk, todo junto), pero nos gusta más.

No nos gustó como iba el logo y el nombre

Esta fue una prueba rápida pero inmediatamente nos demostró que el nombre era muy largo, si bien se pueden hacer algunas magias de diseño como achicar los conectores (in the) u otras cosas, la verdad es que yo tampoco estaba muy contento con el nombre. Hacía un par de semanas que tenía en la cabeza que el nombre hiciera más hincapié en la base del gameplay que es tu relación con los seres del bosque. De ahí viene Woods Folk, literalmente Gente del Bosque.

Carga de Escenas

Esto costó un poco más de lo que pensé, pero ya está listo.

Pudimos usar SVGs como formato intermedio para la definición de las escenas.

¿Qué quiere decir esto? Que Juli puede usar un editor vectorial como Inkscape o Illustrator para definir qué objetos van y dónde en las escenas, salvarlo como .svg y yo corro un "compilador" que agarra ese .svg y lo transforma en un formato propio .scene que nos sirve dentro del motor.

Implementación

🚨 Toda esta sección es para programadores. La podés saltear si no te interesa la programación.

Para no reinventar la rueda utilizamos un crate que se llama... svg.

Para los que no conozcan el formato svg, es básicamente xml, pero con tags estándard asociados al dibujo vectorial. Para los que no conozcan xml, se parece mucho al html, los tags se abren con <tag> y se cierran con </tag>. ¿Y los que no conozcan html... que hacen leyendo esta sección? 💚

El crate que usamos hace lo mínimo indispensable para poder trabajar con svgs: parsea los tags y sus atributos.

A nivel lógico es bastante simple, la biblioteca te da una lista de "eventos", que en sí son cada tag, y cada evento puede ser "principio" y "fin" (asociado con los tags que son y ).

El loop se resume en lo siguiente:

for event in svg::open(&path, &mut content).unwrap() {
  if let Event::Tag(tag, tag_type, attributes) = event {
    match tag {
      "svg" => {
        if tag_type == svg::node::element::tag::Type::Start {
          // ...
        }
      }
      "g" => match tag_type {
        svg::node::element::tag::Type::Start => {
          // ...
        }
        svg::node::element::tag::Type::End => {
          // ...
        }
        _ => {}
      },
      "image" => {
        if tag_type == svg::node::element::tag::Type::Start {
          // ...
        }
      }
    }
  }
}

A nosotros nos interesan particularmente 3 tags:

  • svg: es el tag principal, acá determina el tamaño de la escena. Nosotros estamos diseñando el juego en 4k, así que en general nuestras escenas fijas son de 3840x2160 pero tenemos algunas escenas que van a poder scrollear, por eso usamos este tag para determinar el tamaño.
  • g: en svg el tag g define "grupos". O sea, un conjunto de tags agrupados con alguna lógica. Nosotros usamos el tag g para definir capas para los assets. Para las escenas de los laberintos tenemos 2 capas Platform y Sprites. La primera (Platform) la usamos para poner el piso donde Abril camina, esto está siempre atrás de Abril. La segunda (Sprites) es la capa que tiene todos los objetos con los que Abril puede colisionar y que la tapan si ella pasa por detrás. Si así lo quisiésemos podríamos agregar más capas si queremos que haya cosas más adelante (o más atrás para hacer paralaje).
  • image: este tag es simplemente una referencia a una imágen. Puede ser un árbol, una roca, el piso, lo que sea. Lo importante es que nosotros vamos a usar el nombre del archivo como identificador para después buscar las colisiones, animaciones o propiedades que le queramos poner a ese objeto.

Transformación de Coordenadas

Algo importante a tener en cuenta si implementás un parser de svg, es que normalmente los motores de videojuegos utilizan el centro de los assets como el origen ((0,0)), mientras que los svg utilizan el margen superior izquierdo. Esto hace que no se pueda usar directamente la transformación que te viene en el atributo:

Por ejemplo si este fuese el tag de una imágen:

<image width="78" height="60" id="mushrooms" xlink:href="./sprites/mushroom_1.png"  transform="matrix(0.85 0 0 0.85 1558 1406)">

Ven que la matriz de la transformación dice que la ubicación es (1558, 1406). Ese punto ubica el vertice superior izquierdo del asset a 1558 px en x y 1406 px en y del margen superior izquierdo. Por ende para usarlo en un motor de juegos hay que aplicar una pequeña transformación para reubicarlos:

transform.position_x = transform.position_x - scene_width / 2.0
  + (asset_width * transform.scale_x) / 2.0;
transform.position_y = transform.position_y - scene_height / 2.0
  + (asset_height * transform.scale_y) / 2.0;

Esto es bastante simple, se resta la mitad del ancho y la mitad del alto de la escena, y se le suma la mitad del ancho del asset. Como la posición y la escana están asociadas, hay que aplicar la escala al ancho del asset al centrarlo, por eso se multiplica por transform.scale_*).

Como si esto fuera poco, en svg el eje y crece para abajo, y en los motores normalmente crece para arriba, así que también hay que invertir el eje y.

transform.position_y = -transform.position_y;

Con eso ya está, las cosas deberían quedar ubicadas en la posición adecuada.

En la serialización en json de la escena, ese asset quedó así:

{
  "asset": "mushroom_1",
  "width": 78.0,
  "height": 60.0,
  "transform": {
    "scale_x": 0.85,
    "scale_y": 0.85,
    "rotation_x": 0.0,
    "rotation_y": 0.0,
    "position_x": -328,
    "position_y": -351
  }
}

Y en el juego:

Los honguitos ubicados

Mini-mapa

Parte de la carga de escenas dejó todo listo para implementar el minimapa, así que aproveché y también hice eso. Ahora al caminar se van descubriendo los tiles del mapa uno por uno, limpiando un "Fog of War" tan característico de los RPGs.

Mini-Mapa

Esto la verdad no trajo ningún problema, fue bastante simple de implementar, no creo que haya nada muy interesante para contar acá en cuanto a la implementación.

Bueno, tal vez una cosa que tangencialmente viene al caso, como expliqué en el post anterior, al tener separada la lógica de rendering de la lógica interna del estado, pude implementar la actualización del minimapa simplemente escuchando el mismo mensaje que uso para cambiar de escena TileChangedEvent, sin tener que tocar código en los otros sistemas.

Lo que más me gusta de esta arquitectura es que al tener cada evento definido como un struct con su propio tipo, es fácil encontrar ejemplos de su uso en el código y el compilador se asegura de que no estés haciendo lío. Esto fue un problema en Nubarrón porque teníamos una cola de eventos dinámica donde los eventos se definían con strings y no había forma de validar que estén bien. ¡Ugh!

Narrativa

Ahora que cuentitos está funcionando, pude empezar a escribir el script de la narrativa del juego.

Ya estoy delimitando los primeros personajes en los que voy a estar trabajando, hice una "intro" cortita pero efectiva por ahora, voy a ver si después la desarrollo un poco más.

En las próximas semanas querría empezar a pensar un poco cómo voy a implementar el loop de conversaciones con cuentitos, espero que las cosas que pensé funcionen y sino será momento de volver a mejorar el lenguaje jaja (suena never ending story atrás).

Arca

Acá pongo algunos concepts que hizo Juli de Arca (sí, en honor a Arca), une bruje que está buscando su propio camino después de heredar el negocio de pociones mágicas de su madre.

Arca

Arca

Sapo y Rana

Sapo y Rana son una pareja que vive recluída en el bosque, no es fácil encontrarlos. Los 90s no fueron muy inclusivos y tuvieron que irse lejos. A pesar de lo mal que hablan las personas del bosque de ellos, vamos a aprender a apreciarlos.

Están obviamente inspirados en Frog & Toad. 💚 🏳️‍🌈

Arca

cuentitos

Hoy podemos decir que la versión 0.2 de cuentitos está lista.

Por el uso que le estuvimos dando (no mucho pero tampoco poco), creemos que no tiene bugs muy gruesos, así que el próximo paso es escribir, escribir y escribir.

Entre esta semana y la próxima vamos a escribir un post de lanzamiento y crear un sitio con downloads. Estoy pensando también en hacer un stream y grabarlo para mostrar los features del motor.

Laidaxai

✍ En estas últimas dos semanas, nos hemos reacomodado para continuar con el desarrollo de Laidaxai. Un hito importante fue correr una parte de la narrativa escrita en Cuentitos.

🎮 También estuvimos revisando nuestros documentos de diseño con la participación de Guido, lo que nos ha permitido ordenar y darle sentido al enjambre de textos que circulaban en nuestro proceso de diseño. 😬

🌟 Con Cuentitos en marcha, todo parece estar en movimiento. Ahora, nuestro siguiente paso es experimentar para contar este gran sueño de Laidaxai de una manera poco convencional, tal como suelen ser los sueños.

Objetivos

En las próximas 5 semanas queremos trabajar en:

2dcl

  • Login con Metamask (2dcl Grant): Ya tenemos el 80% de esto resuelto. A partir del 1ro de Agosto vamos a integrarlo con el cliente.
  • Deployment (2dcl Grant): Falta resolver el upload de los archivos a Catalyst y ver si la lógica de firma está bien. Si eso está bien, cuando terminemos con el Login vamos a integrarlo con el cliente también a partir del 1ro de Agosto.
  • Videos de deployment: Apenas terminemos de implementar el deployment simplificado voy a grabar unos videos para documentar todo el proceso de creación de escenas.

Woods Folk

  • Carga de escenas: Vamos a terminar de implementar la carga de escenas desde SVGs. Hecho!
  • Movimiento de personaje: Vamos a implementar todo lo que tiene que ver con el movimiento de Abril en los laberintos.
  • Stream sobre carga de escenas: Al final implementé las escenas y no streamee. 😞
  • Features de Visual Novel: Vamos a integrar cuentitos con woods y comenzar a implementar todas las features de diálogo.
  • Implementar el mapa en stream: Bueno, ahora sí, voy a empezar a streamear esta semana. Martes y Jueves. Para no hacer lío con la hora pueden entrar en el cronograma en nuestro Twitch. Lo primero que quiero hacer es implementar el mapa. Los streams van a ser en ingles, pero nada prohibe que responda en español si es necesario.

Cuentitos

  • CLI watch mode: Entre otras cosas quiero tener un modo watch donde el CLI esté escuchando si se cambia el script y te pregunte si lo querés recompilar y recargar.
  • Lanzamiento: Vamos a hacer el lanzamiento de la versión 0.2 (¡Por fin!). Esto implica crear una página, un posteo en el blog, poner la documentación a mano y la descarga en github.
  • Grabar video explicativo: Quiero grabar un video o hacer un stream sobre cómo escribir scripts en cuentitos.

Laidaxai

  • Continuar con la narrativa de Laidaxai: Aplicando cambios para que funcionen los diálogos en base al diseño del juego. Limitamos algunas apariciones de personajes. Y otras las ponemos como condición.
  • Cinemáticas Laidaxai: Arte nuevo para cinemáticas, estamos experimentando con un estilo paper cut o simulándolo, story board + concept.
  • Continuación del GDD y prototipado: Se está continuando el GDD con toda la información y se está prototipando las mecánicas en el videojuego Table Top Simulator.

Comunidad

  • Comenzar a stremear: Como comenté en la sección de Woods Folk, voy a empezar a streamear los Martes y Jueves. Sigannos en Twitch: https://www.twitch.tv/hiddenpeopleclub/schedule
  • Agregar comentarios al blog: un blog sin comentarios no es un blog. Así que voy a evaluar las distintas opciones que tenemos para implementar comentarios acá. Tengo ganas de usar Mastodon como sistema de comments, o webmentions, no se, ya veremos.
Te gusta lo que hacemos?
Sumate a nuestra lista de correo para recibir notificaciones de nuestras actualizaciones y lanzamientos.