Generating Tile Images III (GameWorld 12)
Time for the next level in tile-generating :).
Last time we looked at generating a range of simple shapes, like balls, trees and bricks. This time around, I am adding a new range of filters to the tile maker, so that you get rid of that cartoony look, at least a little bit.
It is but a single step on my enormous quest to generate nice-looking tiles without having to resort to pixel-painting ;).
Dither
This first one is simple. You pick a color, and then sprinkle x% of the tile with that color at random.
It's a very useful technique, and in retro RPGs you will often find dithering in grass tiles, water tiles or sand tiles.
Dithering as it was used in Mystic Quest. Courtesy of *Hardcoregamer.com*.
To do dithering we first have to have a randomly shuffled list of all pixels in a given tile. You can do that using this function:
def random_pixels():
# build a list with all the pixel coordinates.
pixels = []
for x in range(48):
for y in range(48):
pixels.append((x, y))
# randomly take elements from the first list to build a second one.
pixels2 = []
while len(pixels) > 0:
i = random.randrange(len(pixels))
pixels2.append(pixels[i])
del pixels[i]
return pixels2
Now, randomizing becomes quite simple, because we just take a bunch of elements from our shuffled list of pixels. To make using the function easy, I define an intensity parameter, which can be set between 0.0 (0% dithering) and 1.0 (100% dithering).
Now using the building block above, and my previous code, I can make a dither function like this:
def dither(t, i, color, intensity):
d,x,y,tw,th = t.get_properties(i)
coords = tp.random_pixels()
threshold = int(len(coords) * intensity)
for j in range(threshold):
xj = coords[j][0]
yj = coords[j][1]
tp.pixel(t, i, color, xj, yj)
Here is an example of a simple dithered tile:
And you use the following code to make it:
tp.draw_plain(t, <tile_index>, "#999")
te.dither(t, <tile_index>, "#222", 0.1)
Noise
A Noise filter distort colors, e.g. it can turn a blue square into a square with varying types of blueish colors. In the most extreme case, you can get tiles with simply randomly colored pixels everywhere.
To distort colors of a single pixel, we can use the following:
def color_noise(rgb, intensity):
intensity *= 255
distortions = (int((random.random() - 0.5) * intensity), int((random.random() - 0.5) * intensity), int((random.random() - 0.5) * intensity))
return constrain(rgb[0] + distortions[0], rgb[1] + distortions[1], rgb[2] + distortions[2], rgb[3])
Once again, an intensity of 0.0 is no distortion, and 1.0 almost complete distortion.
I then made a color_filter function that simply applies a function like this to a full tile:
def apply_color_filter(t, i, filter_func, intensity):
d,x,y,tw,th = t.get_properties(i)
for xi in range(0, tw+1):
for yi in range(0, th+1):
color_hex = tp.rgb_to_hex(filter_func(tp.get_rgb(t,i,xi,yi), intensity))
tp.pixel(t, i, color_hex, xi, yi)
Right now I only use it once, but I figured I may be needing something like this in the future ;).
Anyway, this then makes the noise function quite easy to write. Here it is:
def noise(t, i, intensity):
apply_color_filter(t, i, color_noise, intensity)
Noisy tiles can then look like this:
Now that could work reasonably well for a sand tile, right?
It could also look like this, if you go on full random by the way ;):
Closing thoughts
But wait! At the top of the page you can see even more tiles, right? Indeed, I also developed an effect to add a drop shadow, a top highlight, and even a generator to make random stony patterns (that one took AAAAAAAGES by the way!).
But adding those here would make this post a bit bulky, so I will be sharing those somewhere in the next few days :).
Until then, please do let me know if I could explain any part of this tutorial more clearly, as I'm happy to make changes.
Lastly, I have a working repl.it of the tile generator (including early versions of the additions explained in the next blog post!) here.
Continue reading with a Coil membership.