1
\$\begingroup\$

I have been using pygame to make a simple rpg pokemon style game. To create maps I have used the Tiled map editor and then loading them into pygame using pytmx.

I have heard that you can add object layers in Tiled to your map, and then use this information for collision detection within your game engine (in this case pygame). Unfortunately, while I know how to load the tmx file into my pygame game, I have no idea how to use the object layers for collision detection.

Can anyone provide a minimal example on how to do this? The documentation that I have come across for Tiled appears to be quite minimal and still an active work in progress. As a result I have not been able to find information on using Tiled and object layers for collision detection in pygame.

\$\endgroup\$
1
  • \$\begingroup\$ Instead of using an object you could use tile properties, so each tile would have a canWalk property set. Them when you load your map, you test what tile you currently are. Then you check if that tile is walkable and allow walk or not depending on what value that property has. \$\endgroup\$
    – rlam12
    May 23, 2016 at 22:53

1 Answer 1

2
\$\begingroup\$

Since no other solution to this question has been posted - and I now know a solution - I figured I would answer my own question so it may be useful for others.

Consider the Tiled map that looks like this:

enter image description here

and here is the corresponding .tmx file:

<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" renderorder="right-down" width="25" height="25" tilewidth="32" tileheight="32" nextobjectid="2">
 <tileset firstgid="1" name="black" tilewidth="32" tileheight="32" tilecount="1">
  <image source="filename1.png" trans="ff00ff" width="32" height="32"/>
 </tileset>
 <tileset firstgid="2" name="blue" tilewidth="32" tileheight="32" tilecount="1">
  <image source="filename2.png" trans="ff00ff" width="32" height="32"/>
 </tileset>
 <layer name="background" width="25" height="25">
  <data encoding="base64" compression="zlib">
   eJxjZGBgYBzFo3gUj2IkzATFQ92OUTyKR/EoHs4YABD8AnY=
  </data>
 </layer>
 <objectgroup name="hit block">
  <object id="1" x="384" y="318" width="63" height="64"/>
 </objectgroup>
</map>

The following small pygame program shows how collision detection between a red sprite and the blue box can be implemented. You move the red square using the arrow keys and when it intersects with the blue box we get a print statement to the screen. Here is the Python code:

import pygame
import pytmx
from pytmx.util_pygame import load_pygame

# initialize pygame
pygame.init()
clock = pygame.time.Clock() 

# create game display
game_display = pygame.display.set_mode((800, 800))
pygame.display.set_caption("Collision detection with Tiled and pytmx")
red = pygame.Color(153,0,0)
pytmx_map = load_pygame("test.tmx") 


class Block(pygame.sprite.Sprite):
    def __init__(self, color, width, height):
       pygame.sprite.Sprite.__init__(self)

       self.image = pygame.Surface([width, height])
       self.image.fill(color)
       self.rect = self.image.get_rect()

       self.movement_dict = {'left': (-2,0), 'right': (2,0), 'down': (0,2), 'up': (0,-2), 'rest': (0,0)}
       self.movement = 'rest'

    def update(self, event):
        if event != None:
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    quit()
                elif event.key == pygame.K_LEFT:
                    self.movement = 'left'
                elif event.key == pygame.K_RIGHT:
                    self.movement = 'right'
                elif event.key == pygame.K_DOWN:
                    self.movement = 'down'
                elif event.key == pygame.K_UP:
                    self.movement = 'up'
            elif event.type == pygame.KEYUP:
                self.movement = 'rest'

        self.rect.x += self.movement_dict[self.movement][0]
        self.rect.y += self.movement_dict[self.movement][1]

    def draw(self, display):
        display.blit(self.image, self.rect)


block = Block(red, 32, 32)
background = pygame.Surface((25*32, 25*32))
loop = True
event = None
while(loop):
    for event in pygame.event.get():
        pass

    layer_index = 0
    for layer in pytmx_map.visible_layers:
        if isinstance(layer, pytmx.TiledTileLayer):
            for x in range(0, 25):
                for y in range(0, 25):
                    image = pytmx_map.get_tile_image(x, y, layer_index)
                    if image != None:
                        background.blit(image, (32*x, 32*y))
        layer_index += 1
        if isinstance(layer, pytmx.TiledObjectGroup):
            if layer.name == "hit block":
                for obj in layer:
                    if pygame.Rect(obj.x, obj.y, obj.width, obj.height).colliderect(block.rect) == True:
                        print "YOU HIT THE RED BLOCK!!"
                        break

    block.update(event)
    game_display.blit(background, (0,0))
    block.draw(game_display)
    clock.tick(60)
    pygame.display.update()
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .