This example builds on the Sprite Sheet example to show a more sophisticated usage of TileGrid. We'll show how you can have more than one TileGrid and that a TileGrid can be more than just one tile.
The castle wall tiles used in this example were borrowed from this excellent tilesheet: dungeontileset-ii
A Sprite and Its Castle
Our first TileGrid will be another sprite - so a TileGrid with a single tile. This is the same as was done in the Sprite Sheet example. Our second TileGrid will be a little more interesting. It will have more than one tile and will be used to generate the walls and floor of a 2D castle for our sprite to live in.
The idea is to generate the walls and floors by reusing the same source tile over and over. For example, we can create something that looks like this:
You can kind of already see the grid like repetitive pattern. Let's put a reference grid over the top:
This grid is 6 tiles wide by 5 tiles high. You can see how the floor is just the same tile over and over. The walls can similarly be created by reusing the same source tile. So we just need a source bitmap that has each of these basic building pieces. It can come from the same bitmap we'll use for our sprite. Let's do that - here's our new sprite sheet we will work with:
Another super tiny BMP! Here's what it looks like more blown up:
There are a couple of characters we can use for our sprite at the top. But there's also the basic building blocks needed for our castle.
For this example, each item is 16 pixels by 16 pixels. So we'll end up carving up the sprite sheet like this:
As mentioned above, our castle is 6 tiles wide by 5 tiles high. So that will be the size of the TileGrid we'll create to generate the castle. Then, each tile in the castle TileGrid just needs to be set to the correct index from the source bitmap.
Here's what that would look like:
But keep in mind this is only one of the TileGrids we'll create. The other is our simple single tile TileGrid - the sprite. It comes from the same sprite sheet.
Think of it working like this:
And we can assign the single tile of sprite or any of the tiles of castle to any of the indices from sprite_sheet. The (x, y) notation for a couple of tiles in castle are shown as a helpful reminded of how they are accessed.
For example, to set the lower right corner located at (5, 4) of the castle to the "lower right corner" graphic found at index 11 in the sprite_sheet, do this:
castle[5, 4] = 11
But of course we need to set all of the tiles. This just ends up being more lines of code.
Here's the full code:
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries # # SPDX-License-Identifier: MIT import board import displayio import adafruit_imageload display = board.DISPLAY # Load the sprite sheet (bitmap) sprite_sheet, palette = adafruit_imageload.load("/castle_sprite_sheet.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) # Create the sprite TileGrid sprite = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width = 1, height = 1, tile_width = 16, tile_height = 16, default_tile = 0) # Create the castle TileGrid castle = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width = 6, height = 5, tile_width = 16, tile_height = 16) # Create a Group to hold the sprite and add it sprite_group = displayio.Group() sprite_group.append(sprite) # Create a Group to hold the castle and add it castle_group = displayio.Group(scale=3) castle_group.append(castle) # Create a Group to hold the sprite and castle group = displayio.Group() # Add the sprite and castle to the group group.append(castle_group) group.append(sprite_group) # Castle tile assignments # corners castle[0, 0] = 3 # upper left castle[5, 0] = 5 # upper right castle[0, 4] = 9 # lower left castle[5, 4] = 11 # lower right # top / bottom walls for x in range(1, 5): castle[x, 0] = 4 # top castle[x, 4] = 10 # bottom # left/ right walls for y in range(1, 4): castle[0, y] = 6 # left castle[5, y] = 8 # right # floor for x in range(1, 5): for y in range(1, 4): castle[x, y] = 7 # floor # put the sprite somewhere in the castle sprite.x = 110 sprite.y = 70 # Add the Group to the Display display.root_group = group # Loop forever so you can enjoy your image while True: pass
If you run that, you should end up with something like this:
Order Matters
Note the order in which the sprite_group
and the castle_group
were added to the main group that was finally shown on the display.
group.append(castle_group) group.append(sprite_group)
Think of it as building from the bottom up or outward from the display. Each new item will be shown above the previous items. Since we want our sprite to be seen above the castle, we add (append) it after we add the castle.
Using Different Scale
This example shows how you can mix different scales if you want. Since scale
is used at the Group level and applies to everything in the Group, we created two separate Groups for the sprite and castle. That way we could set a different scale for the castle.
You don't have to do this. We could have just added the sprite and castle to the same Group. But this shows how there is flexibility in how you setup your collection of items that you send to the display.
Change The Sprite
Want Adabot to be in the castle instead of Blinka? All you need to do is change the source index for the sprite tile. There are two ways you could do this.
The first would be to use the default_tile
parameter assignment when creating the TileGrid. In the code above, it was set to 0. If you wanted Adabot, you would change it to 1.
The second way would be to just set it after the TileGrid is created. That would look like this:
sprite[0] = 1
Change Sprite Location
Want Blinka to be somewhere else in the castle? Simple, just change the x
and y
values here:
sprite.x = 110 sprite.y = 70
Even more fun - write a loop with these changing inside the loop. Then Blinka will be moving around in the castle!
Text editor powered by tinymce.