PVG
14. Parsing Ldtk Data — Program Video Games

14. Parsing Ldtk Data

[[programvideogames]]In this lecture we'll be parsing the data from our LDtk level.

For now, we'll just focus on creating solid tiles where the solid tiles should be.

Odin comes with a JSON parser built in, and the LDtk is JSON - so that's handy.

Later, we'll want to write smaller JSON (or a custom format - that's more fun), that we could ship with the game because LDtk files are massive.

Before we edit the loading data, we'll define some types that the JSON parser will need:

LDtk_Data :: struct {
    levels: []LDtk_Level,
}

LDtk_Level :: struct {
    identifier:     string,
    layerInstances: []LDtk_Layer_Instance,
}

LDtk_Layer_Instance :: struct {
    __identifier:    string,
    __type:          string,
    __cWid, __cHei:  int,
    intGridCsv:      []int,
    autoLayerTiles:  []LDtk_Auto_Layer_Tile,
    entityInstances: []LDtk_Entity,
}

LDtk_Auto_Layer_Tile :: struct {
    px: [2]f32,
}

LDtk_Entity :: struct {
    __identifier: string,
    __worldX:     f32,
    __worldY:     f32,
}

Here's the new loading data in full.

We entirely replace the old code with this.

// Load level data
{
    level_data, ok := os.read_entire_file("data/world.ldtk", allocator = context.allocator)
    assert(ok, "Failed to load level data")

    ldtk_data := new(LDtk_Data, context.temp_allocator)
    err := json.unmarshal(level_data, ldtk_data, allocator = context.temp_allocator)
    if err != nil {
        fmt.println(err)
        return
    }

    for level in ldtk_data.levels {
        if level.identifier != "Level_0" do continue

        for layer in level.layerInstances {
            switch layer.__identifier {
            case "Entities":
                for entity in layer.entityInstances {
                    switch entity.__identifier {
                    case "Player":
                        px, py := entity.__worldX, entity.__worldY
                        gs.player_id = entity_create(
                            {
                                x = px,
                                y = py,
                                width = 16,
                                height = 38,
                                move_speed = 280,
                                jump_force = 650,
                                on_enter = player_on_enter,
                                health = 5,
                                max_health = 5,
                                debug_color = rl.GREEN,
                                texture = &player_texture,
                                animations = {
                                    "idle" = player_anim_idle,
                                    "jump" = player_anim_jump,
                                    "jump_fall_inbetween" = player_anim_jump_fall_inbetween,
                                    "fall" = player_anim_fall,
                                    "run" = player_anim_run,
                                    "attack" = player_anim_attack,
                                },
                                current_anim_name = "idle",
                            },
                        )
                    case "Door":
                    }
                }
            case "Collisions":
                x, y: f32
                for v, i in layer.intGridCsv {
                    if v != 0 {
                        append(&gs.solid_tiles, Rect{x, y, TILE_SIZE, TILE_SIZE})
                    }
                    x += TILE_SIZE
                    if (i + 1) % layer.__cWid == 0 {
                        y += TILE_SIZE
                        x = 0
                    }
                }
            }
        }
    }
}

This code is following the LDtk JSON structure, loading the player position and solid tiles.