Skip to content

LDtk Settings

Shmellyorc edited this page Sep 3, 2026 · 1 revision

The Problem

LDtk allows you to add custom fields to levels, layers, and entities. These fields can be of many types: integers, floats, booleans, strings, colors, points, enums, file paths, tile references, entity references, and arrays of any of these.

The problem is that LDtk stores these as JSON data. Most integrations give you raw JSON and force you to manually parse each field. This is error-prone, slow, and creates a lot of garbage.

What Void Does

Void provides a strongly typed setting system that handles all the parsing for you. Each setting is stored as a typed LDtkSetting object, and you access values using type-safe methods.

How It Works

When the LDtk map loads, the JSON is parsed once. Each setting is converted to the appropriate strongly typed object. The settings are stored in a dictionary keyed by hash for O(1) lookups.

JSON: { "__identifier": "Health", "__type": "Int", "__value": 100 }
      |
      +-- LDtkIntSettings: Value = 100 (int)

Strongly Typed Settings

Each setting is a strongly typed class that inherits from LDtkSetting.

// These are the actual types used
LDtkBoolSettings       // bool
LDtkIntSettings        // int
LDtkFloatSettings      // float
LDtkStringSettings     // string
LDtkColorSettings      // Color
LDtkPointSettings      // Vect2
LDtkTileSettings       // LDtkTile
LDtkEntityRefSettings  // LDtkEntityRef
LDtkEnumSettings       // string (enum value as string)
LDtkFilePathSettings   // string

Array Variants

All setting types have array variants.

LDtkBoolArraySettings       // List<bool>
LDtkIntArraySettings        // List<int>
LDtkFloatArraySettings      // List<float>
LDtkStringArraySettings     // List<string>
LDtkColorArraySettings      // List<Color>
LDtkPointArraySettings      // List<Vect2>
LDtkTileArraySettings       // List<LDtkTile>
LDtkEntityRefArraySettings  // List<LDtkEntityRef>
LDtkEnumArraySettings       // List<string>
LDtkFilePathArraySettings   // List<string>

Accessing Settings

Use the LDtkSetting static class to access values. The methods use hash-based lookups and Try patterns.

var settings = level.Settings;

// Get a boolean setting
if (LDtkSetting.TryGetBoolSetting(settings, "IsActive", out bool isActive))
{
    // Use isActive
}

// Get an integer setting
if (LDtkSetting.TryGetIntSetting(settings, "Health", out int health))
{
    // Use health
}

// Get an enum setting
if (LDtkSetting.TryGetEnumSetting<EnemyType>(settings, "Type", out var type))
{
    // Use type
}

// Get a point setting
if (LDtkSetting.TryGetPointSetting(settings, "SpawnPoint", out Vect2 spawnPoint))
{
    // Use spawnPoint
}

// Get a tile setting
if (LDtkSetting.TryGetTileSetting(settings, "TileName", out var tile))
{
    // Use tile
}

// Get an entity reference setting
if (LDtkSetting.TryGetEntityRefSetting(settings, "TargetEntity", out var entityRef))
{
    // Use entityRef
}

Array Settings

// Get an integer array setting
if (LDtkSetting.TryGetIntArraySetting(settings, "Waypoints", out var waypoints))
{
    foreach (int point in waypoints)
    {
        // Use point
    }
}

// Get a point array setting
if (LDtkSetting.TryGetPointArraySetting(settings, "Path", out var path))
{
    foreach (Vect2 point in path)
    {
        // Use point
    }
}

// Get an enum array setting
if (LDtkSetting.TryGetEnumArraySetting<EnemyType>(settings, "SpawnTypes", out var types))
{
    foreach (var type in types)
    {
        // Use type
    }
}

Performance

The setting system is designed for performance and GC friendliness.

Hash-Based Lookups

Settings are stored in dictionaries keyed by hash. Lookups are O(1).

// Name is hashed once
settings.ContainsKey(HashHelper.Cache32(name));

// The hash is used directly in the lookup
settings.TryGetValue(HashHelper.Cache32(name), out var result);

No String Parsing at Runtime

All parsing happens once when the map loads. When you access a setting, the value is already typed and ready to use.

// No parsing happens here
int health = LDtkSetting.GetIntSetting(settings, "Health");

GC Friendly

The setting system is designed to minimize garbage collection.

When the LDtk map loads, the JSON is parsed once and all settings are converted to their strongly typed objects. This happens during the initial load and never again. The settings are then stored in dictionaries and reused for the lifetime of the map.

When you access a setting, you are retrieving an object that already exists. There are no allocations. No temporary objects. No parsing. Just a dictionary lookup and a cast.

Operation Allocation
Initial map load All settings created once
Lookup by name None
Getting a value None (already typed)
Getting an array None (already stored)
Repeated lookups None

This means you can access settings every frame without worrying about GC pressure.

No String Comparisons

The system uses hash-based lookups instead of string comparisons. This is faster and avoids the overhead of string comparisons.

// What actually happens
settings.TryGetValue(HashHelper.Cache32("Health"), out var result);

// Not this
settings.TryGetValue("Health", out var result);

Try Methods

All setting access uses Try methods. This means no exceptions are thrown for missing settings. The system returns false and you handle the fallback.

if (LDtkSetting.TryGetIntSetting(settings, "Health", out int health))
{
    // Setting exists, use it
}
else
{
    // Setting doesn't exist, use default
    health = 100;
}

This is faster and cleaner than throwing and catching exceptions.

LDtkSetting Class

The LDtkSetting class is the base for all setting types.

public class LDtkSetting(object value)
{
    public object Value { get; } = value;

    public T ValueAs<T>() => (T)Value;

    // Static helper methods for all types
    public static bool GetBoolSetting(...);
    public static bool TryGetBoolSetting(...);
    // ... and so on for all types
}

Type Mapping

LDtk Type Void Type
Int LDtkIntSettings (int)
Float LDtkFloatSettings (float)
Bool LDtkBoolSettings (bool)
String LDtkStringSettings (string)
Color LDtkColorSettings (Color)
Point LDtkPointSettings (Vect2)
Tile LDtkTileSettings (LDtkTile)
EntityRef LDtkEntityRefSettings (LDtkEntityRef)
LocalEnum LDtkEnumSettings (string)
FilePath LDtkFilePathSettings (string)
Array<Int> LDtkIntArraySettings (List)
Array<Float> LDtkFloatArraySettings (List)
Array<Bool> LDtkBoolArraySettings (List)
Array<String> LDtkStringArraySettings (List)
Array<Color> LDtkColorArraySettings (List)
Array<Point> LDtkPointArraySettings (List)
Array<Tile> LDtkTileArraySettings (List)
Array<EntityRef> LDtkEntityRefArraySettings (List)
Array<LocalEnum> LDtkEnumArraySettings (List)
Array<FilePath> LDtkFilePathArraySettings (List)

Quick Example

// Load the map
var map = AssetManager.Instance.Load<LDtkMap>("levels/world.ldtk");

// Get a level
var level = map.GetLevelByName("Level_01");

// Access level settings
if (LDtkSetting.TryGetStringSetting(level.Settings, "LevelName", out string levelName))
{
    Console.WriteLine($"Level: {levelName}");
}

// Get an entity
var entity = map.GetEntityById("abc-123-def-456");

// Access entity settings
if (LDtkSetting.TryGetIntSetting(entity.Settings, "Health", out int health))
{
    Console.WriteLine($"Health: {health}");
}

if (LDtkSetting.TryGetEnumSetting<EnemyType>(entity.Settings, "Type", out var type))
{
    Console.WriteLine($"Enemy Type: {type}");
}

if (LDtkSetting.TryGetPointArraySetting(entity.Settings, "Waypoints", out var waypoints))
{
    foreach (var point in waypoints)
    {
        Console.WriteLine($"Waypoint: {point}");
    }
}

Back to Home

Clone this wiki locally