Adding Tilemap Component to ECS

So, today I started to make a tilemap component and map system. I already typed TileComponent class last week. I could read the file with txt extension successfully. I edited it though. TileComponent takes the following arguments:

  • File source (example: map.txt)
  • Tileset image (it consists of multiple tiles)
  • Tile size (example: 32px)
I used to Aseprite for making an instance tileset as 96x96. Each tile's dimension should be 32x32 according to this we will pass tile size argument as 32. In addition, this tileset contains 9 tiles. A tileset base grass image to use:
Tileset
1. Tileset image as 96x96
I will use this tileset to tilemap's view. For a natural look, each tile will be located randomly on the map. The render operation just works for part of the image. We do this with the blit function. 
self.app.screen.blit(self.entity.components["TILEMAP_COMPONENT"].tileset, #image
(
    col * self.entity.components["TILEMAP_COMPONENT"].tilesize, # x
    row * self.entity.components["TILEMAP_COMPONENT"].tilesize  # y
), 
(
    self.entity.components["TILEMAP_COMPONENT"].tilesize * random.randint(0,2), # random tile as part of tileset | x-axis
    self.entity.components["TILEMAP_COMPONENT"].tilesize * random.randint(0,2), # random tile as part of tileset | y-axis
    self.entity.components["TILEMAP_COMPONENT"].tilesize,                       # tilesize
    self.entity.components["TILEMAP_COMPONENT"].tilesize                        # tilesize
))

This is how the map.txt file looks like:

If tile is b which means "base" tile then draw random tile part of tileset on the screen.

I created a map entity with TileMapComponent for my game like this:
self.map_entity = Entity(self, [
    TileMapComponent(MAP_1, BASE_TILESET, 32)
])
And then we can use this entity as a map with MapSystem if we process it:
self.mapSystem = MapSystem(self, self.entityManager.entities)
self.mapSystem.process()
The result I got it:
Pygame Tilemap

Well, TileMapComponent and Map system work properly. However, entity sprites doesn't seem normal. I removed screen.fill() line code but I have to, otherwise the tilemap won't be seen because of screen.fill(). mapSystem.process worked once. It isn't in game loop. Let's add it in the loop:
Pygame Tilemap

This is chaos. But it's useful. If you notice, there is one "2" character in map.txt so because of that we have a gap and the white color sprite leaves a scar on map. We have to stop changing tiles for each loop frame. It's easy just remove the random seed from the loop. But first, I want to see FPS of creepy game:
Pygame Tilemap
I ran into some problems while I was trying to addding the fps text to the game. Apparently, I didn't use pygame.display.flip() function correctly. That's should be like this:

def run(self):
    self.playing = True
    while self.playing:
        self.dt = self.clock.tick(60) / 1000
        self.events()
        self.update()
        self.draw()
        self.show_fps()
        pygame.display.flip()
My fps is fixed below 60. If I remove 60 value from tick parameter:
Pygame Tilemap

We already know that but the problem is about performance. I think if we stop the changing of tileset's images then we can get better values of the FPS, we have to stop anyway. I created a random_seed in TileMapComponent:
class TileMapComponent(Component):
		...
        
        self.random_seed = []
        self.random_length = self.tileWidth * self.tileHeight
        for i in range(self.random_length):
            self.random_seed.append(random.randint(0,2))
Now we can use this list of random_seed in MapSystem:
self.app.screen.blit(self.entity.components["TILEMAP_COMPONENT"].tileset, #image
(
    col * self.entity.components["TILEMAP_COMPONENT"].tilesize, # x
    row * self.entity.components["TILEMAP_COMPONENT"].tilesize  # y
), 
(
    self.entity.components["TILEMAP_COMPONENT"].tilesize * self.entity.components["TILEMAP_COMPONENT"].random_seed[self.counter], # random tile as part of tileset | x-axis
    self.entity.components["TILEMAP_COMPONENT"].tilesize * self.entity.components["TILEMAP_COMPONENT"].random_seed[self.counter + 1], # random tile as part of tileset | y-axis
    self.entity.components["TILEMAP_COMPONENT"].tilesize,                       # tilesize
    self.entity.components["TILEMAP_COMPONENT"].tilesize                        # tilesize
))
Let's look the result:
Pygame Tilemap

Yes, it looks better now. Not bad but not enough, I'm already thinking about tilemap editor for this. This is just a try. I think that's enough for blog post. 

No comments:

Post a Comment