First of all, thanks to everyone contributing with testing, issues and pull requests! Today, TileMapDual v4.0 is a great Godot plugin thanks to you!
Now, thanks to the amazing work by raffimolero, the first development version of TileMapDual v5.0 is available for testing on GitHub, under the v5.0.0-dev branch. This represents a full rewrite, so bugs are expected. Please, feel free to try this new version, to report issues and to submit pull requests with your ideas.
Happy coding!
Introducing TileMapDual: a simple, automatic and straightforward custom TileMapLayer
node for Godot that provides a real-time, in-editor and in-game dual-grid tileset system, for both square and isometric grids.
This dual-grid system, as explained by Oskar Stålberg, reduces the number of tiles required from 47 to just 15 (yes, fifteen!!), rocketing your dev journey!
Not only that, but if your tiles are symmetrical, you can get away with drawing only 6 (six!) tiles and then generating the 15-tile-tilesets used by TileMapDual, thanks to tools like Wang Tile Set Creator.
Using a dual-grid system has the following advantages:
- Only 15 tiles are required for autotiling, instead of 47
- The tiles can have perfectly rounded corners
- The tiles align to the world grid
TileMapDual is installed as a regular Godot plugin.
Just copy the addons/TileMapDual
folder to your Godot project, and enable it on Project, Project settings..., Plugins.
You have to create a TileMapDual
node with your own 2x2 tileset, following the standard godot tileset.
And that's it! You can now start sketching your level with the fully-filled tile, indicated here:
You can also sketch with the empty tile in the bottom-left corner, or erase tiles as usual. The dual grid will update in real time as you draw!
The examples
folder has several example scenes. A simple use case with square tiles is provided in the Jess scene.
You can modify the dual tileset in-game by calling the draw()
method as follows:
TileMapDual.draw(cell: Vector2i, tile: int = 1, atlas_id: int = 0)
Where:
cell
is a vector with the cell positiontile
is1
to draw the full tile (default),0
to draw the empty tile, and-1
to completely remove the tileatlas_id
is the atlas id of the tileset to modify, 0 by default
Note: the new
draw()
method replaces the deprecatedfill_tile()
anderase_tile()
methods.
The included CursorDual
node provides an example use case to modify the tiles in-game.
An additional method, TileMapDual.update_full_tileset()
, is available to refresh the entire dual grid. It should not be necessary, but may come in handy in case of a hypothetical bug.
Isometric tilemaps are compatible with the TileMapDual
node.
You heard that right, isometric, as in 'isometric'. It works automatically, out of the box. Isometric tilemaps! yayyyy!
An use example is provided in the Isometric scene.
To use isometric tilemaps, all you need to do is follow an isometric-ed version of the standard godot tileset template that we previously used for square tilemaps, as shown in the image below:
This isometric tileset can be drawn by hand. But it can also be drawn more easily using a tool like TileCropper, a Godot plugin that allows you to draw the tiles in one continuous image, to later separate the tiles as follows:
That's it. Just 15 tiles for isometric autotiling. I love it.
You can use multiple atlases in the same tileset. To change them in-game, make sure you call the draw()
method described above with the desired atlas_id
, which is 0
by default. An example is included with the custom CursorDual
node, see the MultipleAtlases scene.
Note that each atlas can handle 2 surfaces. To add more surfaces or tile variations on top of one another, consider using a second TileMapDual
node with transparencies in your tileset, just as you would do with a regular TileMapLayer
. An example is provided in the MultipleLayers scene.
Due to the unique implementation of TileMapDual, shaders and materials may not work as expected in some cases. As a temporary work-around, a material slot, Display Material
is provided, which you'll find at the top of the node properties. Any ShaderMaterial
or Material
added there will automatically be propagated to the displayed tilemap.
Note: changes made to the
CanvasLayer
Material
and orSelf Modulate
slot will be, upon scene reload, copied toDisplay Material
and or the displayed tilemap'sself_modulate
before being cleared (set tonull
). This is necessary to prevent rendering of the parentTileMapDual
.
This release simplifies the implementation of a dual-grid system by introducing a simple custom node that runs automatically and in-editor, making it easy to integrate into your own projects.
Previous implementations of a dual-grid tileset system in Godot, mainly by jess::codes and GlitchedInOrbit, were not automatic and required extensive manual configuration (at the time of writing). These implementations also used an inverted version of the standard 16-tile template (although Jess's tileset is provided as an example in this repo). This is a potential source of headaches, and this release corrects said inversion.
This release also implements modern TileMapLayers instead of the deprecated TileMap node.
Plus, you can use multiple atlases in the same tileset.
Oh, and also... You can use isometric tilesets!
This project is Open Source Software, released under the MIT license. This basically means that you can do whatever you want with it. Enjoy!
This repo is open to pull requests, just make sure to check the contributing guidelines. I personally encourage you to send back any significant improvements to this code so that the Godot community continues to thrive. Thanks!
- Dual grid Twitter post by Oskar Stålberg
- 'Programming Terrain Generation' video by ThinMatrix
- 'Drawing Fewer Tiles' video by jess::codes
- jess::codes implementation in C#
- GlitchedInOrbit implementation in GDScript
- Wang Tile Set Creator
- Webtyler tool, to convert from 15-tile sets to 47-tile sets
Please feel free to contact me to provide feedback, suggestions, or improvements to this project. You may also check the the contributing guidelines to submit an issue or a pull request :D