Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
88c2ba0
Add support for hex and iso grids from tiled tile layers
Insality Dec 24, 2025
3e52d55
Update object positions
Insality Dec 24, 2025
9ddef2c
Fix for position z of objects
Insality Dec 25, 2025
a9d3f6f
Update
Insality Dec 29, 2025
bed6405
Update
Insality Feb 14, 2026
19470cd
Update
Insality Feb 14, 2026
7f29ba4
Update
Insality Feb 14, 2026
71717ae
Update
Insality Feb 14, 2026
87a0fdf
Update
Insality Feb 14, 2026
e2b2169
Update
Insality Feb 14, 2026
4121be0
Update
Insality Feb 14, 2026
b105388
Update
Insality Feb 14, 2026
9dfd990
Update
Insality Feb 14, 2026
c301db7
Isogrid example
Insality Feb 14, 2026
c3e8c7c
Add isometric module
Insality Feb 14, 2026
aeac304
Update
Insality Feb 14, 2026
ffe4bd3
Update
Insality Feb 14, 2026
b614920
Update
Insality Feb 14, 2026
8f235ab
Update
Insality Feb 14, 2026
3437d88
Remove detiled_system
Insality Feb 14, 2026
a8b8c08
Rename detiled_decore -> detiled_parser
Insality Feb 14, 2026
c2dbb58
Update
Insality Feb 14, 2026
8a3a82d
Update
Insality Feb 14, 2026
9e537ad
Update
Insality Feb 14, 2026
d1e7af8
Update
Insality Feb 14, 2026
c5b98df
hex pointy top
Insality Feb 14, 2026
2672f5c
Update
Insality Feb 14, 2026
678e544
Update
Insality Feb 14, 2026
739f9d5
Update
Insality Feb 14, 2026
e17a890
Update
Insality Feb 15, 2026
84416cd
Update
Insality Feb 15, 2026
ff77d27
Fixes for isometric
Insality Feb 15, 2026
b5f5c7b
Update
Insality Feb 15, 2026
5991a2b
Update
Insality Feb 15, 2026
1702828
Update
Insality Feb 15, 2026
f80a98d
Update
Insality Feb 15, 2026
33e169e
Add even/odd for the hexagonal staggered index support
Insality Feb 15, 2026
8a4abfc
Update
Insality Feb 15, 2026
96b5daa
Update
Insality Feb 15, 2026
42f3e73
stagger axis for isometric staggered
Insality Feb 15, 2026
646dcd6
Update iso position
Insality Feb 15, 2026
9b1e779
Update
Insality Feb 15, 2026
da69d8e
Update
Insality Feb 16, 2026
6475a3b
Update wasd camera
Insality Feb 16, 2026
4a9365d
Entity optimization
Insality Feb 16, 2026
0f07e4a
tiled id as number
Insality Feb 16, 2026
da80f51
Refactor
Insality Feb 16, 2026
f0938c9
Add ellipse point polygon polyline and rectangle object types
Insality Feb 16, 2026
20cc8f1
Use layer excluded
Insality Feb 16, 2026
bb36e97
Refactor hex grids
Insality Feb 16, 2026
21ca219
Update
Insality Feb 16, 2026
9c4acc0
Update annotations
Insality Feb 16, 2026
bb3e8d2
Update
Insality Feb 16, 2026
bfbb627
Update
Insality Feb 17, 2026
9778cd7
Update logo imaegs
Insality Feb 20, 2026
0ff8971
Update deps
Insality Feb 20, 2026
fc28c7d
Update examples
Insality Feb 20, 2026
1ca35dd
Add image field to the parsed entities from tilesets
Insality Feb 20, 2026
3ca3fb7
Update example with one game object multiple sprites
Insality Feb 20, 2026
f1b50db
Add grid game objects example
Insality Feb 23, 2026
35c4bd0
Update
Insality Mar 3, 2026
81b246c
Update
Insality Mar 3, 2026
7f5a790
Update
Insality Mar 4, 2026
ccd7c81
Transform as separate table, debug logs
Insality Mar 10, 2026
956435e
Update
Insality Mar 15, 2026
f49c0c9
Don't log whole map
Insality Apr 9, 2026
5496b93
Update annotations, rename get_entity_from_map to parse, update examples
Insality Apr 13, 2026
af93103
Update API
Insality Apr 13, 2026
60864a3
Update API and docs
Insality Apr 13, 2026
a3f57d5
Add rotation to example
Insality Apr 13, 2026
b018d99
Add adjusting entity position docs
Insality Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ Thumbs.db
.project
.cproject
builtins
/.editor_settings
/.editor_settings
*.tiled-session
208 changes: 152 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,27 @@

# Detiled

**Detiled** - is a Defold library that converts [Tiled](https://www.mapeditor.org/) maps and tilesets into [Decore](https://github.com/Insality/decore) entities.
**Detiled** is a Defold library that converts [Tiled](https://www.mapeditor.org/) maps and tilesets into easy-to-use entities. It supports all Tiled grid types: orthogonal, hexagonal, and isometric.

## Features

- Load tilesets with prefab definitions and component properties
- Convert Tiled maps to Decore entities
- Use class names as prefab IDs, with fallback to image names
- Support for custom properties and components from Tiled
- Load tilesets and parse maps to get map entities
- Use prefab IDs to spawn game entities
- Adjust entity properties from tilesets and maps
- Convert cell indices to world position and vice versa


### Setup

Open your `game.project` file and add the following line to the dependencies field under the project section:

**[Decore](https://github.com/Insality/decore)**
**[Detiled](https://github.com/Insality/detiled/archive/refs/tags/3.zip)**

```
https://github.com/Insality/decore/archive/refs/tags/3.zip
https://github.com/Insality/detiled/archive/refs/tags/3.zip
```

**[Detiled](https://github.com/Insality/detiled/archive/refs/tags/2.zip)**

```
https://github.com/Insality/detiled/archive/refs/tags/2.zip
```

After that, select `Project ▸ Fetch Libraries` to update [library dependencies]((https://defold.com/manuals/libraries/#setting-up-library-dependencies)). This happens automatically whenever you open a project so you will only need to do this if the dependencies change without re-opening the project.
After that, select `Project ▸ Fetch Libraries` to update [library dependencies](https://defold.com/manuals/libraries/#setting-up-library-dependencies). This happens automatically whenever you open a project, so you only need to do this if dependencies change without re-opening the project.

### Library Size

Expand All @@ -49,64 +43,157 @@ After that, select `Project ▸ Fetch Libraries` to update [library dependencies

## Setup

### Workflow

1. Load all tilesets before loading maps:
```lua
local detiled = require("detiled.detiled")
### Tiled

Tiled is a map editor for creating 2D games. It is used to create maps and tilesets for your game.
Detiled supports tilesets and exports maps as Lua table entities for Defold, which can be used to spawn game entities.


#### Creating Tilesets

Detiled supports collection-of-images tilesets, because each tile should have an associated prefab. Single-image tilesets are not supported.

Create a new tileset and add images to it. Usually, you will have a `/tiled` folder with all Tiled files for the project. Place the tileset inside `/tiled/tilesets` and add this folder as a custom resource in `game.project`.

```init
[project]
custom_resources = /tiled/tilesets
```

Each tile in a tileset has a `prefab_id`, which will be available in your Defold project. By default, `prefab_id` is the image name without extension. For example, `player.png` becomes `player`. You can change `prefab_id` in the tileset editor by setting the tile `class`. This way, one image can have multiple `prefab_id` values.


#### Creating Maps

Create a new map and save it in `/tiled/maps` with the `.json` extension. Since Detiled loads JSON files, this keeps the workflow simple.

To load JSON files, add this folder as a custom resource in `game.project`.

```init
[project]
custom_resources = /tiled/tilesets,/tiled/maps
```

Now you can create tile and object layers and place entities directly on the map.
You can also add shapes (rectangle, point, polygon, polyline, ellipse) directly on the map. Since these entities have no tileset tile associated with them, they have no `prefab_id` by default. You can assign a `prefab_id` by setting a `class` on the map object.

Each tile from a tileset will be exported as a single entity.


#### Custom Properties

Tiled has good support for custom properties. Open `View -> Custom Types Editor` and add custom classes with the properties you need.
You can add and override custom properties on tiles in tilesets or directly on object instances in maps. In `Custom Types Editor`, use defaults only as editor-time templates, because this default data is not exported to Defold.


-- Load all used tilesets first before loading maps
detiled.load_tileset("/resources/tilesets/my_tileset.json")
```
### Defold

2. Convert Tiled maps to Decore entities:
```lua
-- Get entity prefab from map
local map = detiled.get_entity_from_map("/resources/maps/my_map.json")
When tilesets and maps are ready, you can spawn entities.

-- Add to Decore world
world:addEntity(decore.create(map))
```
Detiled library provides a simple API to parse maps and tilesets.

```lua
detiled.load_tileset(tileset_path_or_data) -- required before parsing a map
detiled.parse(map_path_or_data) -- returns layers, map_params
```

### Prefab ID Resolution

Prefab IDs are determined in this order:
1. `class` field from the tile or object in Tiled
2. `type` field as fallback
3. Image filename (without path/extension) as final fallback
#### Loading Tilesets

First, load the tileset used by your maps.

```lua
local detiled = require("detiled.detiled")
detiled.load_tileset("/tiled/tilesets/my_tileset.json")
```

### Object Types
#### Parsing Maps

- **Tile Objects** - Objects with `gid` (from tileset) use tileset properties
- **Class Objects** - Objects with `class` field spawn as that prefab type
- **Empty Objects** - Objects without `gid` or `class` spawn as basic entities
Then parse a map to get a layers table and `map_params` as the second return value.

### Custom Properties
```lua
local layers, map_params = detiled.parse("/tiled/maps/my_map.json")
```

To override component properties from Tiled:
`layers` is a table with layer id as key and layer data as value. Layer data contains an `entities` list and layer properties. Iterate over it to create game objects.

1. **Setup Custom Types in Tiled**:
- Go to `View -> Custom Types Editor`
- Add your custom class with the property name matching your component
- Example: Create a `movement` class with `stick` (bool) and `speed` (int) properties

2. **Use in Tilesets or Maps**:
- Add the custom property to tiles in tilesets or directly to object instances in maps
- Properties with `propertytype` matching the property name become components
```lua
---@param entity detiled.entity
---@param layer_data detiled.layer_data
local function spawn_entity(entity, layer_data)
local prefab_id = entity.prefab_id
local transform = entity.transform

local position = vmath.vector3(
transform.position_x + layer_data.position_x,
transform.position_y + layer_data.position_y,
transform.position_z + layer_data.position_z
)
local scale = vmath.vector3(transform.scale_x, transform.scale_y, 1)
local rotation = vmath.quat_rotation_z(math.rad(transform.rotation or 0))

local factory_url = "/entities#" .. prefab_id
factory.create(factory_url, position, rotation, nil, scale)
end


---@param layers detiled.layers
local function spawn_map(layers)
for layer_name, layer_data in pairs(layers) do
local entities = layer_data.entities
local layer_position_x = layer_data.position_x -- Horizontal offset from layer settings
local layer_position_y = layer_data.position_y -- Vertical offset from layer settings
local layer_position_z = layer_data.position_z -- From position_z custom property on layer settings
local is_visible = layer_data.visible

for _, entity in ipairs(entities) do
spawn_entity(entity, layer_data)
end
end
end
```

3. **Property Override Hierarchy** (highest priority first):
- Map instance properties
- Tileset properties
- Entity definition properties
- Default Decore component values
If you add custom properties to an entity in a tileset or map, they are available on the parsed entity.

Example: If an entity has `movement = { can_jump = true, speed = 20 }` by default, you can override just the `speed` in Tiled while keeping `can_jump = true`.
```lua
local function spawn_entity(entity, layer_data)
local prefab_id = entity.prefab_id
local my_component = entity.my_component
if my_component then
print(my_component.value)
end

-- rest of the code
end
```

### Layer Properties

Layers support special properties:
- `position_z` - Sets the Z position for all entities spawned from this layer
- Objects can have their own `position_z` property that gets added to the layer's `position_z`
- `exclude` *(boolean)* - This layer is skipped and not parsed
- `position_z` *(number)* - Base Z for entities spawned from this layer

Entities support specific properties:
- `position_z` - A position_z for the entity transform
- `width` and `height` - Width and height of the entity, available only when `prefab_id` is missing


### Cell to Position and Position to Cell

Detiled provides a simple API to convert cell indices to world position and vice versa.

```lua
local layers, map_params = detiled.parse("/tiled/maps/my_map.json")
detiled.cell_to_pos(i, j, map_params) -- returns x, y
detiled.pos_to_cell(x, y, map_params) -- returns i, j
```


### Adjusting Entity Position

You can set an `anchor` position for an entity in the tileset. This is useful when your Defold game object anchor differs from the sprite center. For example, a tree game object is usually placed on the ground. To adjust its placement, open the tileset, select the tree tile, and open `Tile Collision Editor`. Then add a `Point` object at the desired sprite anchor position. This point is used to calculate the final entity position in Defold.


## Game Example
Expand All @@ -120,8 +207,10 @@ Look at [Shooting Circles](https://github.com/Insality/shooting_circles) or [Cos

```lua
detiled.set_logger(logger_instance)
detiled.load_tileset(tileset_path_or_data)
detiled.get_entity_from_map(map_path_or_data)
detiled.load_tileset(tileset_path_or_data) -- required before parsing a map
detiled.parse(map_path_or_data) -- returns layers, map_params
detiled.cell_to_pos(i, j, map_params) -- returns x, y
detiled.pos_to_cell(x, y, map_params) -- returns i, j
```

### API Reference
Expand Down Expand Up @@ -153,6 +242,13 @@ For any issues, questions, or suggestions, please [create an issue](https://gith
### **V2**
- Reworked API and documentation

### **V3**
- Unbind from Decore library
- Rename `detiled.get_entity_from_map` to `detiled.parse`
- Add `detiled.cell_to_pos` and `detiled.pos_to_cell` API
- Rework map parse return params, now it's a layers table with entities and properties with map_params as second return value
- Add all grid types support, not only orthogonal. All hexagonal and isometric grids are supported.

</details>

## ❤️ Support project ❤️
Expand Down
55 changes: 47 additions & 8 deletions api/detiled_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
## Functions

- [set_logger](#set_logger)
- [get_entity_from_map](#get_entity_from_map)
- [parse](#parse)
- [cell_to_pos](#cell_to_pos)
- [pos_to_cell](#pos_to_cell)
- [load_tileset](#load_tileset)


Expand All @@ -21,21 +23,57 @@ Set a logger instance
- **Parameters:**
- `[logger_instance]` *(table|detiled.logger|nil)*:

### get_entity_from_map
### parse

---
```lua
detiled.get_entity_from_map(map_or_path)
detiled.parse(map_or_path)
```

Load a tiled map as a Decore entity
You can add this entity with `world:addEntity(entity)`
Get layers and map params from a map. Each layer has entities, properties, layer_id, visible, position (offset).

- **Parameters:**
- `map_or_path` *(string|detiled.map)*:

- **Returns:**
- `` *(entity)*:
- `` *(table<string, detiled.layer_data>)*:
- `` *(detiled.map_params|nil)*:

### cell_to_pos

---
```lua
detiled.cell_to_pos(i, j, map_params)
```

Convert cell indices to world position

- **Parameters:**
- `i` *(number)*:
- `j` *(number)*:
- `map_params` *(detiled.map_params)*:

- **Returns:**
- `` *(number)*:
- `` *(number)*:

### pos_to_cell

---
```lua
detiled.pos_to_cell(x, y, map_params)
```

Convert world position to cell indices

- **Parameters:**
- `x` *(number)*:
- `y` *(number)*:
- `map_params` *(detiled.map_params)*:

- **Returns:**
- `` *(number)*:
- `` *(number)*:

### load_tileset

Expand All @@ -44,10 +82,11 @@ You can add this entity with `world:addEntity(entity)`
detiled.load_tileset(tileset_or_path)
```

Load a tileset
Load a tileset to internal cache, so maps can reference it by name while parsing

- **Parameters:**
- `tileset_or_path` *(string|detiled.tileset)*:
- `tileset_or_path` *(string|detiled.tileset)*: Path to tileset JSON file or tileset table

- **Returns:**
- `` *(detiled.tileset)*:

Loading
Loading