Adding tile images/groups + views on XRP & why we do this (GameWorld 9)
In this installment of Coil-monetized Brython game development, we will be adding tile images. We are building on the previous tutorial, where we added support for touch screens and mouse handlers, but where the tiles were still rather basic colored squares.
Intro: it is a good day to be monetized!
It seems like ages ago, but back in December I made a first simple demo that combined a Brython-based browser game in repl.it with Coil monetization. Now coding in Brython can sometimes be a bit harder than other platforms, so it's good to remind people why it's worth it.
Essentially, when users open your Brython game and play it, the Coil ticker starts counting just like it would for a Coil blog post, a Cinnamon or monetized YouTube video, or for a Simmer.io Unity-based game (yes, life is indeed much easier if you want to monetize a Unity game, but I'm unfortunately a hardcore Python fan when it comes to my hobbies, hence this blog series ;)).
All this is already great, because you can get some monetary rewards for your creative efforts without going through (a) the Seven Layers of Sales Marketing Hell or (b) the Nine-Hundred-Eighty-Five Layers of Finding non-Intrusive Yet Effective Advert Placements Hell.
A second benefit is that you although can receive this payment through a currency that this man has a strong hand in:
Image courtesy of *Pixabay*. It is supposed to depict the POTUS on a happy day.
...you could also opt for the XRP currency which is much less directly tied to the whims of a particular national leader. (As a side comment, someone should really fix this redirect from XRP to Ripple, which I linked to above, and make a dedicated XRP page on Wikipedia (!)).
Aside from having the vague ambition of being an early adopter, I especially like this alternative because I'm not so impressed by the leaders of the major countries in the world today ;). And if I am to believe the local Twitter bot about XRP/fiat trading going on (who goes by the artist name of @LiquidityB), then it seems I'm part of a growing group these days.
Anyway, enough blather about the payments, onwards to the game development!
Step 1: Getting an image of the tiles
I will cover tile making separately in a future installment, but for purposes of this tutorial, I will simply reuse this image with 48x48 tiles that probably last looked cutting edge in 1992 ;):
Quite importantly, in this tutorial we're going to number the tiles from 0 all the way to 39, with the first row being 0,1,2,3, the second row 4,5,6,7 and so on.
Great, that was quick then! On to step 2:
Modifying the tile rendering process
Just as a reminder, we are doing this tutorial in a series, so it's probably easiest to fork my GameWorld 7 repl.it, and take that as a starting point. All the changes we do in this subsection will be in Tiles.py
.
The first thing we need to do is to load our image into the repl.it. To do this, we need to upload the image to the repl.it server's main directory. After that, you add the following line to the initialization function of your Tiles class (called __init__()
):
self.tile_img = html.IMG(src="tiles.gif")
This ensures that the gif image with all the tile graphics is available within the Tiles class :). Note that you can also use other formats, such as .jpg (not recommended) or .png (definitely recommended!).
Now, we of course need to display the tiles in the appropriate way. To do this, we write a brand new show()
function for the Tiles classs. We do that as follows:
def show(self, screen, x, y, width, height):
We start of by (again) defining the tile range in x and y direction that will be shown on the screen:
txstart = int(x/self.tilesize)
txend = int(math.ceil((x + width) / self.tilesize))
tystart = int(y/self.tilesize)
tyend = int(math.ceil((y + height) / self.tilesize))
We then iterate over those two tile ranges to draw each of the individual tiles:
for i in range(txstart, txend):
for j in range(tystart, tyend):
We obtain the coordinate for the top left coordinate of the tile to draw:
xtile = i * self.tilesize - x
ytile = j * self.tilesize - y
And the index number of the tile we wish to draw.
tile_num = self.tiles[i][j]
As a reminder, we count tiles from left to right, and then from top to bottom. So the tile_num is 0 for the top left tile, 1 for the tile to the right of it, and 4 for the leftmost tile on the second row. Lastly, we draw the tile image, by selecting the right region in the tiles.gif image, and rendering that to screen.
screen.drawImage(self.tile_img, (tile_num%4)*49, int(tile_num/4)*49, 48, 48, xtile, ytile, 48, 48)
To be exact, the region we select starts at x = (tile_num%4)*49, y = int(tile_num/4)*49, and is 48x48 pixels in size.
Now, with all these things in place, we are ready to render images!
Making a tile group
Now the graphics look a bit better than they did before, but it's still tedious to manually insert tiles with statements like:
tiles.tiles[4][4] = 0 # a small pond
Fortunately, this can be solved very easily, and in this last part I'll explain how to do so.
In your main.py
file, we currently do the tile drawing, but we can make this easier with functions that create groups of tiles. As an example, a group of tiles could be a house, a lake, a wall or a very large tree.
As a primer for you I'll present a simple tile group function to draw the insides of a house. At a later stage I'll show how to make a roof and other things, because that aspect requires you to learn about multiple map layers (and create them ;)).
Anyway, here is an example of a house tile group function. The function is called makeHouse() and it takes the x and y position for the house, as well as (optionally) its width and height:
def makeHouse(tiles, x, y, w=5, h=5):
# this only makes the inside for now.
h -= 1
# back wall
tiles.fill(8,x,y,w,1)
# front wall (with opening)
tiles.fill(8,x,y+h,int(w/2),1)
tiles.fill(8,x+int(w/2)+1,y+h,w-(int(w/2)+1),1)
# side inside walls
tiles.fill(7,x,y,1,h)
tiles.fill(7,x+w-1,y,1,h)
# floor
tiles.fill(11,x+1,y+1,w-2,h-1)
By using the variables x, y, w and h in the tile fill functions, we've been able to create a house that dynamically resizes and repositions, based on the values we provided to the function. This is great, because we can now call the function twice to make two differently-sized houses in two different locations :), e.g.:
makeHouse(tiles,4,3)
makeHouse(tiles,13,5,w=8)
...and that's all you need. If you put all the code in correctly (and I didn't make a mistake here in the tutorial), then you should get something like this:
Closing thoughts
It's all still very basic, but with mouse movement, animated sprites, text boxes and now tile images and simple houses, I hope you're starting to recognize the outlines of an RPG-style game :). There are so many things to still work on, such as making better tiles, adding layers, adding obstacles or introducing play actions other than talking. My hope is that we'll get around to all of that in not too long :).
Anyway, here is the link to the GameWorld 8 Repl:
https://repl.it/@djgroen/GameWorld-8
And here's a direct link to the game:
https://gameworld-8.djgroen.repl.co/
(monetized to my Coil account, so please fork the Repl and change the Coil pointer if you don't want to sponsor me ;)).
Lastly, for the subscribers I have a little bit more about my view on XRP, and why I chose the angle I did today.