So the experiment that I mentioned in comments totally worked.
- Have your shapes be your base tile textures
- Programmatically create the
TileSet
on your TileMap
- As you're creating tiles on the
TileSet
, also set the modulate
for each Tile
In this way I was able to create a single set of shapes (just two .png
files), and dynamically create colors for every player. I then can set the cells in the TileMap
according to the player that controls that cell.
So, in your example (10 shapes, 15 colors) I think you'd only have to maintain:
- The 10 shape images
- The list of 15 colors
... and your code would programmatically create a TileSet
with 150 tiles in it. Then you just need a bit of logic in your code to select the correct shape + color tile and you're set.
Here's my code, and some screenshots to show what I did:
extends Control
const MWID = 32
const MHGT = 32
const PLAYER_COLORS = [
Color("009BB8"), # light blue
Color("B80D00"), # very red
Color("158C00"), # medium green
Color("D4BC15"), # medium yellow
Color("004BB8"), # dark blue
Color("26E800"), # bright green
Color("E89200"), # medium orange
Color("C800A4") # purple
]
const BASE_TEXTURES = {
"tower": preload("res://sprites/tower.png"),
"pool": preload("res://sprites/pool.png")
}
onready var map = $map
func _ready() -> void:
var ti
var pi
for p in range(PLAYER_COLORS.size()):
ti = p * 2
pi = (p * 2) + 1
map.tile_set.create_tile(ti)
map.tile_set.tile_set_texture(ti, BASE_TEXTURES.tower)
map.tile_set.tile_set_modulate(ti, PLAYER_COLORS[p])
map.tile_set.create_tile(pi)
map.tile_set.tile_set_texture(pi, BASE_TEXTURES.pool)
map.tile_set.tile_set_modulate(pi, PLAYER_COLORS[p])
set_tiles()
func set_tiles() -> void:
for ti in map.tile_set.get_tiles_ids():
map.set_cell(ti, 0, ti)
Scene setup:

Sprite setup:

Final scene:

So, now that we've covered the basics let's take this a bit further. Let's say that you were working on a game that was very TileMap
-based, and let's say that you wanted a feature such that when you hover your mouse cursor over a tile you want that tile to display at 50% opacity, or with a gray overlay or something. What you could potentially do when you're programmatically generating your TileSet
is to duplicate all your tiles - one set was full opacity, and the rest were 50% opacity, and the offset between the two could be chosen in code at runtime as your mouse moves around the screen. This would increase the memory footprint of your TileSet
, but it would also:
- Decrease the total number of images you needed to manage significantly
- Decrease the total game binary size, because there are fewer total images in the first place
You could do some more optimizations based on your use case, but as for something quick + easy + practical, this would be relatively simple.
Alright, finally, you could also extend TileSet
to make this all automatic. Meaning, I think you could attach a normal-looking TileSet
to your TileMap
, use all the TileSet
editing stuff in Godot, but on game load you could programmatically expand + duplicate the tiles in the TileSet
to get your colors and transparency, etc. This way your TileSet
(in the editor) would look very simple and small, but once the game starts and your code expands that TileSet
you can make an n-dimensional TileSet
from your base with very little effort.