whydoitweet

tile

It's a big gap, but GameWorld is back! (at least for now ;)).

Last time, we started with making plain tiles, as well as basic grid and brick structures. Today, I am going to extend this with 3+1 extras:

  • Balls or spheres.
  • 3-dimensional bricks.
  • A basic tree
  • ...and for the Coil subscribers a bonus tile drawing that I made together with my daughter ;).

We are using the same approach as last time (I do recommend doing that tutorial first), but extend it with a few new routines.

Pre-amble: adding shades and highlights

Because several of the shapes need shadows and highlights to give them a 3D look, we start of with making a simple function that creates shadow and highlight color, given a default starting color.

Here is the function to make a shading color, which we put in tile_patterns.py:

def shade(rgb, intensity=2):

tmp = [0,0,0]

for i in range(0, len(rgb)):

tmp[i] = int(rgb[i]/intensity)

return tmp[0],tmp[1],tmp[2]

Simply put, I define a shadow as a color with half of the values of the regular color. And for highlights, I do the opposite, which looks like this:

def highlight(rgb, intensity=2):

tmp = [0,0,0]

for i in range(0, len(rgb)):

tmp[i] = min(255, int(rgb[i]*intensity))

return tmp[0],tmp[1],tmp[2]

Making a (rudimentary) ball or sphere

Now, to make a sphere with highlight and shading, we first need to make a circle. This you can do as follows:

def draw_circle(t, i, color, xc, yc, xc2, yc2):

d,x,y,tw,th = t.get_properties(i)

d.ellipse([x+xc,y+yc,x+xc2,y+yc2],color)

In my simplistic tutorial, I simply make a ball by placing three circles at on top of each other, each with a size and a position that helps convey some depth. This looks as follows:

def draw_ball(t, i, hcolor, color, lcolor, xc, yc, xc2, yc2):

w = xc2-xc

h = yc2-yc

draw_circle(t, i, lcolor, xc, yc, xc2, yc2)

draw_circle(t, i, color, int(xc+w/20), int(yc+h/20), int(xc2-w/8), int(yc2-h/8))

draw_circle(t, i, hcolor, int(xc+w/7), int(yc+h/7), int(xc+w/2.5), int(yc+h/2.5))

Here, lcolor is the shadow color, which is used for the biggest background circle. I then put a slightly smaller circle on top of that, aligned to the top left, with the default color. Lastly, I add a small circle with the highlight color (hcolor) in the top left area of the main circle, to indicate a highlighted region. Combined, this will make a ball roughly like this:

Now, be aware that there are much better ways to do this, but I went straight for simplicity here.

Making a 3D rectangle

Similarly, we can add shading and highlights to rectangles. This we can do as follows:

def draw_3drect(t, i, color, x1, y1, w, h):

rgb = ImageColor.getrgb(color)

w -= 1

h -= 1

d,x,y,tw,th = t.get_properties(i)

We first decide on the size of the shaded and highlighted region, which corresponds to the depth of the rectangle. I chose a ratio of 0.1.

shade_size = 0.1

shade_width = max(1,int(shade_size*w))

shade_height = max(1,int(shade_size*h))

hl_size = 0.1

hl_width = max(1,int(hl_size*w))

hl_height = max(1,int(hl_size*h))

Next we draw the main rectangle (everything else will come on top of it)

draw_rect_hwrap(t, i, color, x1, y1, w, h)

And on the right side and the bottom side, two shaded rectangles:

draw_rect_hwrap(t, i, shade(rgb), (x1+w-shade_width)%tw, y1+hl_height, shade_width, h)

draw_rect_hwrap(t, i, shade(rgb), x1+hl_width, y1+h-shade_height, w-hl_width, shade_height)

Lastly, we draw two highlight rectangles on the left and on the top.

draw_rect_hwrap(t, i, highlight(rgb), x1, y1, hl_width, h-shade_height)

draw_rect_hwrap(t, i, highlight(rgb), x1, y1,w-shade_width, hl_height)

Note that I am using a function called “draw_rect_hwrap() here, which I am about to explain :).

Making 3D looking bricks

To make 3D bricks, we first need 3D rectangles representing each brick. But to make the pattern repeating, we also need those rectangles to wrap properly around the sides of the tile. To do this, we need a special version of draw_rect() which is used in the same way, but wraps around the sides. That one looks like this:

def draw_rect_hwrap(t, i, color, x1, y1, w, h):

d,x,y,tw,th = t.get_properties(i)

if x1+w>tw:

draw_rect(t, i, color, x1, y1, tw-x1, h)

draw_rect(t, i, color, 0, y1, x1+w-tw, h)

else:

draw_rect(t, i, color, x1, y1, w, h)

Now the next step, is to simply place the rectangles side by side, with alternating offsets so that we get a brick pattern. We do that like this:

def draw_3dbrick(t, i, color="#900", width=24, height=12):

d,x,y,tw,th = t.get_properties(i)

row = 0

b = 0

a = 0

while b < th:

while a < tw:

draw_3drect(t, i, "#A22", a, b, width, height)

a += width

b += height

row += 1

a = int(((width)/2) * (row%2))

..and once we do that, we can make a brick like this:

Making a tree

There are a *lot* of ways to make a tree, but a simple one is to simply use a brown stick, and put on it a pattern of green balls. Here's what that looks like in code:

def draw_tree(t, i, hcolor="#4f4", color="#0a0", lcolor="#060"):

d,x,y,tw,th = t.get_properties(i)

d.rectangle([x+20, y+24, x+28, y+48], "#660")

The next line contains all the coordinate pairs where we place the green spheres:

for xy in [[8,9],[18,4],[27,10],[6,19],[20,14],[28,10],[18,24],[28,19]]:

draw_ball(t, i, hcolor, color, lcolor, xy[0], xy[1], xy[0]+16, xy[1]+16)

And when you use this, you get a simple tree like this!

Closing thoughts

It's all very simple stuff still, but I think you get the idea: with each simple drawing function that combines existing drawing functions, we're able to add a little more variety and depth to our tile graphics.

I've added the Repl in the Appendix, and I extended the tile demonstrations, which now look like this:

And the functions to make the last 5 tiles are as follows in main.py:

tp.draw_circle(t, 12, "#DD3", 0, 0, 47, 47)

tp.draw_ball(t, 13, "#FF6","#DD3", "#AA2", 0, 0, 47, 47)

tp.draw_tree(t, 14, "#4f4","#0a0", "#060")

tp.draw_dog(t, 15)

tp.draw_3dbrick(t, 16, "#A22")

Who knows what we'll focus on next? Perhaps it's even more advanced tiles, or perhaps something entirely different....

Appendix 1: Full Repl.

You can find the online runnable Repl.it here: https://repl.it/@djgroen/Gameworld-10-Tile-Generator-II#tile_patterns.py

Read more...