Devlog #8: Talk with the Grant Support squad about 2dcl - Scene loading, new characters, and mini map for Woods Folk (Previously Weekends in the Woods) - Cuentitos v0.2 - Reorganization in Laidaxai
2dcl
I have to admit that in the previous post I unintentionally lied to you.
I said that the next day we were going to start working on 2dcl
, and while that was true and I was working on the Metamask login, in the talk with Pablo from the Grant Support Squad we agreed to start the project on August 1st because of the contract issue.
Login with Metamask
I made a bit of progress on this between Wednesday and Thursday before deciding to wait until the 1st.
I have an open Pull Request about it.
I managed to implement the workflow in a sample file (decoupled from the client).
What we do is pretty simple although cumbersome:
- We create a local web server
- We serve a small dapp with a 'Connect with MetaMask' button.
- Login is made and the Ethereum address used to connect is saved.
This is enough for the client to be able to load the avatar without having to edit the configuration files. The first thing we are going to do starting August 1st is to integrate this small login workflow with our 2dcl
client.
Deployment with MetaMask
I was also able to make some progress with the deployment workflow.
I also have a Pull Request (but in draft).
I haven't yet managed to upload the files, but there's quite a bit of progress, I understood by reading the CLI of the foundation that it is validated with a signature on the entity id, so I implemented that using what I had done for the login as a basis.
Appreciation
I wanted to especially thank the entire Protocol Squad team, product of this grant. The work they are doing not only in terms of documentation but also with the reference implementations is fantastic.
The fact that one of the reference implementations uses Rust, and in particular Bevy, is of great help to a project like ours.
The lack of this documentation is what caused us to have to cancel an important part of our previous grant, which was to automatically transform 3D scenes into 2D. The Protocol Squad's work will enable this feature when the ECS7 has greater penetration in the Decentraland scenes. Thank you!!!
Woods Folk (formerly Weekends in the Woods)
After experimenting with various logos and not finding much taste in the name Weekends in the Woods, we decided to rename the game to Woods Folk, it's not clear that this name will stay (Another option is Woodsfolk, all together), but we like it more.
This was a quick test but it immediately showed us that the name was too long, although you can do some design magic like shrinking the connectors (in the
) or other things, the truth is that I was not very happy with the name either. For a couple of weeks I had in mind that the name should emphasize more on the base of the gameplay which is your relationship with the beings of the forest. Hence comes Woods Folk, literally People of the Forest.
Scene Loading
This took a bit more than I thought, but it's now ready.
We were able to use SVGs as an intermediate format for the definition of the scenes.
What does this mean? That Juli can use a vector editor like Inkscape or Illustrator to define which objects go and where in the scenes, save it as .svg
and I run a "compiler" that grabs that .svg
and transforms it into our own .scene
format that serves us within the engine.
Implementation
To avoid reinventing the wheel, we used a crate called... svg.
For those who are unfamiliar with the svg
format, it's basically xml
, but with standard tags associated with vector drawing. For those who don't know xml
, it looks a lot like html, the tags open with <tag>
and close with </tag>
. And those who don't know html... what are they doing reading this section? ๐
The crate we use does the bare minimum necessary to work with svgs: it parses the tags and their attributes.
At a logical level it's quite simple, the library gives you a list of "events", which are essentially each tag, and each event can be a "start" and "end" (associated with the tags that are
The loop can be summarized as follows:
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 {
// ...
}
}
}
}
}
We are particularly interested in 3 tags:
svg
: this is the main tag, here it determines the size of the scene. We are designing the game in 4k, so in general our fixed scenes are3840x2160
but we have some scenes that will be able to scroll, so we use this tag to determine the size.g
: in svg the tagg
defines "groups". That is, a set of tags grouped with some logic. We use the tagg
to define layers for the assets. For the maze scenes, we have 2 layersPlatform
andSprites
. The first one (Platform
) we use to place the floor where Abril walks, this is always behind Abril. The second (Sprites
) is the layer that has all the objects with which Abril can collide and that cover her if she passes behind. If we wanted to, we could add more layers if we want things to be further ahead (or further behind to create parallax).image
: this tag is simply a reference to an image. It can be a tree, a rock, the floor, whatever. The important thing is that we will use the name of the file as an identifier to later search for the collisions, animations or properties that we want to put on that object.
Coordinate Transformation
An important thing to keep in mind if you are implementing an svg parser is that normally, video game engines use the center of the assets as the origin ((0,0)
), while svgs use the upper left margin. This means that you can't directly use the transformation that comes in the attribute:
For example, if this was the tag for an image:
<image width="78" height="60" id="mushrooms" xlink:href="./sprites/mushroom_1.png" transform="matrix(0.85 0 0 0.85 1558 1406)">
See how the transformation matrix says the location is (1558, 1406)
. This point places the upper left vertex of the asset at 1558
px in x
and 1406
px in y
from the upper left margin. Therefore, to use it in a game engine, a small transformation must be applied to reposition them:
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;
This is quite simple, you subtract half the width and half the height of the scene, and then add half the width of the asset. Since the position and the scene are associated, you have to apply the scale to the width of the asset when centering it, which is why it's multiplied by transform.scale_*
).
As if this wasn't enough, in svg the y
axis grows downwards, and in engines it usually grows upwards, so the y
axis also needs to be inverted.
transform.position_y = -transform.position_y;
With that, things should be positioned in the correct spot.
In the JSON serialization of the scene, that asset ended up like this:
{
"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
}
}
And in the game:
Mini-map
Part of the scene loading process set everything up to implement the mini-map, so I took the opportunity and did that too. Now as you walk, the tiles on the map are revealed one by one, clearing a "Fog of War" so characteristic of RPGs.
Honestly, this didn't pose any problems, it was quite simple to implement, I don't think there's anything very interesting to tell here in terms of implementation.
Well, maybe one thing that tangentially comes into play, as I explained in the previous post, having separated the rendering logic from the internal logic of the state, I was able to implement the mini-map update simply by listening to the same message I use to change scenes TileChangedEvent
, without having to touch code in the other systems.
What I like most about this architecture is that having each event defined as a struct with its own type, it's easy to find examples of its use in the code and the compiler ensures that you're not making a mess. This was a problem in Nubarrรณn because we had a dynamic event queue where events were defined with strings and there was no way to validate that they were correct. Ugh!
Narrative
Now that cuentitos is working, I was able to start writing the script for the game's narrative.
I'm already defining the first characters I'll be working on, I've made a short but effective intro for now, I'll see if I can develop it a bit more later.
In the coming weeks, I'd like to start thinking about how I'm going to implement the conversation loop with cuentitos, I hope the things I've thought about work and if not, it will be time to improve the language again haha (sounds like a never ending story in the background).
Arca
Here I share some concepts that Juli made of Arca (yes, in honor of Arca), a witch who is seeking her own path after inheriting her mother's magic potion business.
Sapo and Rana
Sapo and Rana are a couple who live secluded in the forest, it is not easy to find them. The 90s were not very inclusive and they had to go far away. Despite how badly the people in the forest speak of them, we will learn to appreciate them.
They are obviously inspired by Frog & Toad. ๐ ๐ณ๏ธโ๐
cuentitos
Today we can say that version 0.2
of cuentitos
is ready.
Based on the usage we've been giving it (not a lot but not a little either), we believe that it doesn't have any major bugs, so the next step is to write, write, and write.
Between this week and the next, we are going to write a release post and create a site with downloads. I am also thinking of doing a stream and recording it to showcase the engine's features.
Laidaxai
โ In the last two weeks, we have re-adjusted to continue with the development of Laidaxai. An important milestone was running part of the narrative written in Cuentitos.
๐ฎ We've also been reviewing our design documents with Guido's participation, which has allowed us to organize and make sense of the swarm of texts circulating in our design process. ๐ฌ
๐ With Cuentitos in motion, everything seems to be moving. Now, our next step is to experiment to tell this great dream of Laidaxai in an unconventional way, as dreams usually are.
Goals
In the next 5 weeks, we want to work on:
2dcl
- Metamask Login (2dcl Grant): We already have 80% of this sorted out. Starting from August 1st, we are going to integrate it with the client.
- Deployment (2dcl Grant): We still need to resolve the upload of the files to Catalyst and see if the signing logic is correct. If that's the case, once we finish with the Login, we'll also integrate it with the client starting from August 1st.
- Deployment videos: As soon as we finish implementing the simplified deployment, I'll record some videos to document the entire process of creating scenes.
Woods Folk
Scene Loading: We're going to finish implementing the scene loading from SVGs.Done!- Character Movement: We're going to implement everything related to April's movement in the mazes.
Scene Loading Stream: In the end, I implemented the scenes and didn't stream. ๐- Visual Novel Features: We're going to integrate
cuentitos
with Woods and start implementing all dialogue features. - Implement Map on Stream: Alright, now I'm going to start streaming this week, on Tuesday and Thursday. To avoid confusion with the time, you can check the schedule on our Twitch. The first thing I want to do is implement the map. The streams will be in English, but that doesn't prohibit me from answering in Spanish if necessary.
cuentitos
- CLI watch mode: Among other things, I want to have a
watch
mode where the CLI is listening if the script changes and asks you if you want to recompile and reload it. - Launch: We're going to launch version 0.2 (at last!). This implies creating a page, a blog post, having the documentation at hand, and the download on Github.
- Record explanatory video: I want to record a video or do a stream about how to write scripts in cuentitos.
Laidaxai
- Continue with the narrative of Laidaxai: We are making changes to make the dialogues work based on the game's design. We limit some character appearances and set others as a condition.
- Laidaxai Cinematics: New art for cinematics, we are experimenting with a paper cut style or simulating it, storyboard + concept.
- Continuation of the GDD and prototyping: We are continuing the GDD with all the information and we are prototyping the mechanics in the Table Top Simulator video game.
Community
- Start streaming: As I mentioned in the Woods Folk section, I'm going to start streaming on Tuesdays and Thursdays. Follow us on Twitch: https://www.twitch.tv/hiddenpeopleclub/schedule
- Add comments to the blog: a blog without comments is not a blog. So, I'm going to evaluate the different options we have to implement comments here. I feel like using Mastodon as a comment system, or webmentions, we'll see.
- Version en Espaรฑol ๐ฆ๐ท๐ง๐ด๐จ๐ฑ๐จ๐ด๐จ๐ท๐จ๐บ๐ฉ๐ด๐ช๐จ๐ธ๐ป๐ฌ๐ถ๐ฌ๐น๐ญ๐ณ๐ฒ๐ฝ๐ณ๐ฎ๐ต๐ฆ๐ต๐พ๐ต๐ช๐ช๐ธ๐บ๐พ๐ป๐ช
- English Version ๐ฆ๐ฌ๐ง๐ธ๐ง๐ง๐ง๐ฟ๐ง๐ผ๐จ๐ฆ๐ฉ๐ฒ๐ซ๐ฏ๐ฌ๐ฒ๐ฌ๐ญ๐ฌ๐ฉ๐ฌ๐พ๐ฎ๐ช๐ฏ๐ฒ๐ฐ๐ช๐ฑ๐ท๐ฒ๐ผ๐ฒ๐บ๐ซ๐ฒ๐ณ๐ฌ๐ต๐ฌ๐ฐ๐ณ๐ฑ๐จ๐ป๐จ๐ธ๐ฑ๐ธ๐ฌ๐ธ๐ธ๐น๐น๐ฟ๐ฒ
Comments