2
votes

I've been creating a Map Editor for my game. Basically I establish a grid using a matrix, and then fill it with 20x20 tiles that have an assigned numeric value which can change based on mouse position and the click of a keyboard button. If I wanted to make the top left tile a different color I would assign it to 1:

[
 [1,0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0,0],
]

However, the problem that I ran into now is trying to blit images that are larger than the tiles, instead of just changing the color of the tiles. Since the tiles are only 20x20, only 20x20 of the image shows. Even if I got the whole image to blit, collision detection would never work properly because the image would still only change the one selected index and not all the indices that the image actually covers right? In other words, lets say my image is 40x40. If I successfully blit the whole image to the top left index, objects would still only collide with that 20x20 space right?

If that is true, would there be a way to make it so that all the indices change when I blit the 40x40 image, so it looks like this?

[
 [1,1,0,0,0,0,0,0,0,0],
 [1,1,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0,0],
]

Here is the full code so far:

import pygame

DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
LEAST_DISPLAY_WIDTH = 0
MAX_DISPLAY_WIDTH = 800
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PURPLE = (255, 0, 255)
DIRT = (0, 0, 16, 16)
GREEN = (34,139,34)
YELLOW = (255,255,51)
BROWN = (210,180,140)
BLUE = (0, 255, 255)

pygame.init()
size = (DISPLAY_WIDTH, DISPLAY_WIDTH)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
game_exit = False

class Graph(object):
    def __init__(self, rows=None, columns=None):
        self.rows = rows
        self.columns = columns
        self.grid = []

    def make_graph(self):
        for rows in range(self.rows):
            self.grid.append([])
            for columns in range(self.columns):
                self.grid[rows].append(0)
        return self.grid

class Tile(object):
    def __init__(self, width=None, height=None, color=None, loadedimage=None):
        self.width = width
        self.height = height
        self.color = color
        self.image = pygame.Surface((self.width, self.height))
        if self.color != None:
            self.image.fill(self.color)
        self.loadedimage = loadedimage
        if self.loadedimage != None:
            self.image = pygame.image.load(str(loadedimage))
            self.rect = self.image.get_rect()
            self.width = self.rect.x
            self.height = self.rect.y
        self.image.convert()
        self.rect = self.image.get_rect()


graph = Graph(rows=60, columns=80)
graph.make_graph()

while not game_exit:
    for row in range(graph.rows):
        for column in range(graph.columns):
            if graph.grid[row][column] == 0:
                color = WHITE
                tile = Tile(width=20, height=20, color=color)
            elif graph.grid[row][column] == 1:
                color = None
                #testing for blitting images
                tile = Tile(width=20, height=20, color=color, loadedimage="poro.png")
                # print tile.rect.x, tile.rect.y
            elif graph.grid[row][column] == 2:
                color = BLUE
                tile = Tile(width=20, height=20, color=color)
            elif graph.grid[row][column] == 3:
                color = GREEN
                tile = Tile(width=20, height=20, color=color)
            elif graph.grid[row][column] == 4:
                color = BROWN
                tile = Tile(width=20, height=20, color=color)
            elif graph.grid[row][column] == 5:
                color = YELLOW
                tile = Tile(width=20, height=20, color=color)
            elif graph.grid[row][column] == 6:
                color = BLACK
                tile = Tile(width=20, height=20, color=color)
            screen.blit(tile.image, ((tile.width*column),(tile.height*row)))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_exit = True

        if event.type == pygame.KEYDOWN:
            pos = pygame.mouse.get_pos()
            column = pos[0] // tile.width
            row = pos[1] // tile.height
            if event.key == pygame.K_a:
                graph.grid[row][column] = 1
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)
            if event.key == pygame.K_s:
                graph.grid[row][column] = 2
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)
            if event.key == pygame.K_d:
                graph.grid[row][column] = 3
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)
            if event.key == pygame.K_f:
                graph.grid[row][column] = 4
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)
            if event.key == pygame.K_g:
                graph.grid[row][column] = 5
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)
            if event.key == pygame.K_h:
                graph.grid[row][column] = 6
                print "Position: {0}, Grid Coordinates: {1}, {2}".format(pos, row, column)

    clock.tick(60)
    pygame.display.flip()
print graph.grid
pygame.quit()
1
Are all of your image dimensions an exact multiple of 20? - DJMcMayhem
@DJMcMayhem no, the image provided at the github is 50x50. If I change the tiles to 50x50, of course everything is fine... Also, If I blit the image to its rect.x and rect.y, it blits the whole image. But then I lose control of where I want to place it and it goes to (0, 0). Im sure there is an easy way to place it where I choose, but I think I would still run into the problem of the image overlapping other indices... - thevengefulco
Fixed the rect.x and rect.y problems. I simply used self.rect.width and self.rect.height... still working on the other problem - thevengefulco
I'm quite confused. Are you trying to make a 50x50 surface 20x20? If so, you can use pygame.transform.scale. - Douglas - 15 year old Pythoner

1 Answers

0
votes

The easiest way to fix your image issue would be to transform your image to the tile size using pygame.transform.scale(Surface, (width, height), DestSurface = None), which you can read more about here.

class Tile(object):
    def __init__(self, width=None, height=None, color=None, loadedimage=None):
        self.width = width
        self.height = height
        self.color = color
        self.image = pygame.Surface((self.width, self.height))
        if self.color != None:
            self.image.fill(self.color)
        self.loadedimage = loadedimage
        if self.loadedimage != None:
            self.image = pygame.image.load(str(loadedimage))

            # Scale image to tilesize
            self.image = pygame.transform.scale(self.image,(self.width,self.height))

            self.rect = self.image.get_rect()
            self.width = self.rect.width
            self.height = self.rect.height
        self.image.convert()
        self.rect = self.image.get_rect()

As to the issue with if you do fit the image at its current size, it would have an issue with the collisions falling under just the one origin tile. It would also, however; create the issue of that image overwriting the tiles it overflows to or vice versa so having the image overflow to other tiles is a bad idea.

If you absolutely cannot scale the image, you should split the image into parts, and add the specific parts to their respective tiles.

You can do this by blitting a specific area of the image rather than the whole image.

screen.blit(tile.image,((tile.width*column),(tile.height*row)), (pos_on_image,tile_size) )

In his way, the whole image can be displayed without being scaled while not having the collisions be off or the image overlapping other tiles.