Day 3 – Crying with prefabs


My idea of today's work was pretty simple. I had the sprite rendering set up and could move a tile representing the player character. Next step: replacing the tile with the good old '@' glyph to represent the player. Then, adding some non-player characters using Amethyst's prefab system which adds entities with components from external files. After that I could begin moving ahead to adding simple NPC interaction, like dialogue.

Instead, things happened.

First, as far as I can tell the only way to (currently and out of the box) render text glyphs is using the UI system. However, 1) those elements are placed in screen-absolute coordinates instead of world-relative as other rendered objects, and 2) they require position adjustments to be done separately to sprites.

For the first issue, my world is positioned relative to a grid whose lower-left corner is at (0, 0). The camera is moved over this grid (following the player character), as are all entities. So to find the screen-absolute coordinates for an entity we have to calculate it relative to the camera, which (for now) is positioned exactly in the middle of the screen. Not difficult to adjust, but it still took some time.

Second, I had to rework my system which moves all entities to allow for both the original transform setup when using sprites and the new for glyphs. Again, not super difficult, but refactoring takes time. I ended up moving the sprite/glyph transform step to new, separate systems instead of repositioning them when eg. checking collisions. In the end I think that creating a new rendering pass for glyphs that uses the same world transforms as sprites will be preferable, but all things in due time.

Being overall pleased with my results I moved on to prefabs. Which are explained in several reasonably long guides and examples.

I still could not understand how they work, as if my eyes just glazed across all text without looking at it. It took a lot of time to get to grips with something that seemed easy from the outside.

I think there are two big reasons for my issues. One is that the files which store the assets on disk look like this for a single entity:

Prefab(    
    entities: [
        PrefabEntity(
            data: Player( // Your data starts here
                name: Named(name: "Zero"),
                position: Position(1.0, 2.0, 3.0),
            ),
        ),
    ],
)

That's four steps of indirection until your data shows up. Examples of code are similarly chatty, especially when more than a single component is required.

The second is that I could not work out how to generate additional components for the created entities based on their data. For example, to render a character I'd like to only specify which glyph to use and (for now) whether or not it's the player character or an NPC. A single asset file would be something like (extending it to add more specific information as needed):

Prefab(        
    entities: [
        PrefabEntity(
            data: Character::Player(
                glyph: '@',
            ),
        ),
        PrefabEntity(
            data: Character::NPC(
                glyph: 'c',
            ),
        ),
    ],
)

But I could not work out how to use the prefab system to easily create the text rendering UiText component, which naively has to be specified in full. This would move the file closer to:

Prefab(        
    entities: [
        PrefabEntity(
            data: Character::Player(
                glyph: UiText(
                    font: File(<link to font on disk?>),
                    text: "@",
                    color: [1.0, 1.0, 1.0, 1.0],
                    font_size: 24.0,
                ),
            ),
        ),
    ],
)

That's a lot of additional information that has to be specified for every entity, and a lot of values like font size and colour that could be set using variables. Furthermore, as far as I can tell all of the entity's components have to be specified in the file. I'd prefer to be able to generate a default set if not specified, but could not get a custom adapter to work.

Maybe I'm overlooking some functionality or have misunderstood something.

I have for now created a simple solution similar to the previous file structure. This means that not all of an entity's components are created by the prefab system itself, but through a loading state that reads the prefab, constructs the entities and generates the missing components (including the UiText component based on a single glyph). It works, but I'd prefer to have the actual loader fill in these gaps instead of spreading it out into surrounding systems. 

Hopefully as the engine matures this system will become as easy to use and intuitive as I imagined.

Today's updated code can be found here, with the prefab specification in this file and the loading set-up in this. Maybe I can get around to the actually interesting parts tomorrow. For now there's at least a beautifully rendered '@' (or otherwise if you edit the prefab file) to look at.

Files

windy-city-politics-0.1.2-win.zip 2 MB
Jul 02, 2019

Leave a comment

Log in with itch.io to leave a comment.