If I blit my image onto the main window of pygame, it wont show as expected

Viewed 61

I'm currently trying to develop my first simple indie game in python using the pygame library. Recently I started coding a map editor. Everything works fine, except that if i want to display the map, I get some kind of scaled or "compressed" image (see pictures) It looks like this but it should look like this. Here is my complete code for the map builder:

import Map_
import sheet
import Tile_

FPS = 60
WINDOW_SIZE = (640,480)
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
DEFAULT_TILE_SET = ("roguelikeCity_magenta","png")


class Builder:
    def __init__(self):
        if not pygame.get_init():
            pygame.init()

        self.SCREEN = "MENU"
        self.LEFT_CLICK = False

        self.tilesize = 16
        self.scale_factor = 3
        self.true_tilesize = self.scale_factor*self.tilesize

        self.TILE_SHEET = sheet.Tile_Sheet(DEFAULT_TILE_SET[0],DEFAULT_TILE_SET[1])
        self.MAP = Map_.Map(self.TILE_SHEET,self.true_tilesize)

        self.WINDOW = pygame.display.set_mode(WINDOW_SIZE)
        pygame.display.set_caption("Map Editor v.1")
        self.FONT = pygame.font.SysFont("Arial", 18,True)
        self.CLOCK = pygame.time.Clock()

        self.new_map()

    def quit(self):
        print("Quitting....")
        exit(0)

    def menu(self):
        self.SCREEN = "MENU"
        self.new_map_button = pygame.Rect(0,0,100,25)
        self.new_map_button.center = (WINDOW_SIZE[0]/8,WINDOW_SIZE[1]-100)
        self.exit_button = pygame.Rect(0,0,100,25)
        self.exit_button.center = (WINDOW_SIZE[0]/8,WINDOW_SIZE[1]-70)

    def new_map(self):
        self.MAP.generate_map(32,32,"untitled.json")
        self.SCREEN = "NEW MAP"
        self.save_button = pygame.Rect(0,0,100,25)
        self.save_button.center = (WINDOW_SIZE[0]-100,WINDOW_SIZE[1]-50)

        self.init_tile_list()
        self.init_scrollbar()
    
    def init_scrollbar(self):
        ratio = WINDOW_SIZE[1]/self.Tile_list.h
        self.thumb_w = 20
        thumb_h = WINDOW_SIZE[1]*ratio
        self.thumb_col = (123,123,123)
        scrollbar_x,scrollbar_y = self.Tile_list.w,0
        self.Thumb = pygame.Rect(self.Tile_list.w,0,self.thumb_w,thumb_h)
        self.Scrollbar = pygame.Rect(scrollbar_x,scrollbar_y,self.thumb_w,WINDOW_SIZE[1])
        self.scrollbar_jump = (self.Tile_list.h-WINDOW_SIZE[1])/(WINDOW_SIZE[1]-thumb_h)

    def init_tile_list(self):
        tile_list_count_x = 4
        tile_margin = 4
        tile_list_w = self.true_tilesize*tile_list_count_x+tile_list_count_x*tile_margin
        tile_list_h = int(len(self.TILE_SHEET.Sprites)/4)*(tile_margin+self.true_tilesize)
        self.Tile_list = pygame.Rect(0,0,tile_list_w,tile_list_h)

        self.Tile_list_img = []
        loc = []
        tiles_per_row = int((tile_margin+self.Tile_list.w)/(tile_margin+self.true_tilesize))
        
        margin_counter_x = 0
        margin_counter_y = 0
        for y in range(len(self.TILE_SHEET.Sprites)):
            for x in range(tiles_per_row):
                pos_x = x*self.true_tilesize+margin_counter_x
                pos_y = y*self.true_tilesize+margin_counter_y
                margin_counter_x += tile_margin
                loc.append([pos_x,pos_y])
            margin_counter_x = 0
            margin_counter_y += tile_margin
        
        index_counter = 0
        for img in self.TILE_SHEET.Sprites:
            self.Tile_list_img.append(Tile_.Tile(loc[index_counter][0],loc[index_counter][1],self.TILE_SHEET.get_img(self.TILE_SHEET.get_key(img)),self.TILE_SHEET.get_key(img)))
            index_counter+=1
    
    def move_tile_list(self,chx,chy):
        if not (self.Thumb.y + -chy) < 0 or (self.Thumb.bottomleft + chy) > WINDOW_SIZE[1]:
            self.Thumb.y += -chy
            for tile in self.Tile_list_img:
                tile.move(chx*int(self.scrollbar_jump),chy*int(self.scrollbar_jump))

    def render_builder(self):
        self.display_map()
        for tile in self.Tile_list_img:
            self.display(tile.Image,(tile.pos_x,tile.pos_y),scale=True)
        self.display(self.Scrollbar)
        self.display(self.Thumb,color=self.thumb_col)

    def display_map(self):
        map_pos = (self.Tile_list.w + self.Scrollbar.w,0)
        self.WINDOW.blit(self.MAP.Image_background,map_pos)

    def display(self,what,where=None,color=None,scale=True):
        '''"WHAT" is either a Rect, Surface or String
        If displaying a String, no "WHERE" is needed, otherwise use a Tuple (x,y)
        Default "COLOR" is White, use a tuple to change that (Red,Green,Blue)'''
        if type(what) == pygame.Rect:
            if color:
                pygame.draw.rect(self.WINDOW,color,what)
            else:
                pygame.draw.rect(self.WINDOW,WHITE,what)
        elif type(what) == pygame.Surface:
            what = pygame.transform.scale(what,(self.true_tilesize,self.true_tilesize))
            self.WINDOW.blit(what,where)
        elif type(what) == str:
            if color:
                text_surface = self.FONT.render(what,False,color)
            else:
                text_surface = self.FONT.render(what,False,BLACK)
            text_rect = text_surface.get_rect()
            text_rect.center = where
            self.WINDOW.blit(text_surface,text_rect)

    def update_display(self):
        pygame.display.update()
        self.WINDOW.fill(BLACK)
        if self.SCREEN == "MENU":
            self.display(self.new_map_button)
            self.display("New Map", self.new_map_button.center)
            self.display(self.exit_button)
            self.display("Exit",self.exit_button.center)
        if self.SCREEN == "NEW MAP":
            self.display(self.save_button,self.save_button.center)
            self.display("Save", self.save_button.center)
            self.render_builder()
        pygame.display.flip()

    def check_collide(self):
        if self.SCREEN == "MENU":
            if self.new_map_button.collidepoint(self.mx,self.my) and self.LEFT_CLICK:
                self.new_map()
            if self.exit_button.collidepoint(self.mx,self.my) and self.LEFT_CLICK:
                self.quit()
        if self.SCREEN == "NEW MAP":
            if self.Thumb.collidepoint(self.mx,self.my) and self.LEFT_CLICK:
                self.thumb_col = (255,255,0)
            if not self.LEFT_CLICK:
                self.thumb_col = (123,123,123)
        
    def event_handle(self):
        self.mx, self.my = pygame.mouse.get_pos()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    self.LEFT_CLICK = True
            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    self.LEFT_CLICK = False
            
            if event.type == pygame.MOUSEMOTION:
                if self.SCREEN == "NEW MAP":
                    if self.Thumb.collidepoint(self.mx,self.my) and self.LEFT_CLICK:
                        chy = event.rel[1]
                        self.move_tile_list(0,-chy)
    
    def tick(self):
        self.MAP.tick()
        self.update_display()
        self.event_handle()
        self.check_collide()
        self.CLOCK.tick(FPS)

a = Builder()
while True:
    a.tick()

aswell as the code for the map_.py and chunk_.py files:

import sheet
import json
import Tile_
import Chunk_
import pygame

DEFAULT_TILE = "RENAME_889"

class Map():
    def __init__(self,Sheet_object,tile_size):
        self.MAP = {
            "BACKGROUND":{
                "TILES":[],
                "CHUNKS":[]
            },
            "FOREGROUND":{
                "TILES":[],
                "CHUNKS":[]
            }
        }
        self.Tile_Sheet = Sheet_object
        self.tile_size = tile_size
        self.width = 0
        self.height = 0
        self.chunk_size = 16
        
        self.DEFAULT_TILE_ID = self.Tile_Sheet.get_key(DEFAULT_TILE)
        self.DEFAULT_TILE_IMG = self.Tile_Sheet.get_img(self.DEFAULT_TILE_ID)


    def generate_map(self,w,h,name,DEFAULT_TILE_="RENAME_889"):
        if DEFAULT_TILE_ == 0:
            self.DEFAULT_TILE_ID = -1
            self.DEFAULT_TILE_IMG = pygame.Surface((self.tile_size,self.tile_size))
        else:
            self.DEFAULT_TILE_ID = self.Tile_Sheet.get_key(DEFAULT_TILE_)
            self.DEFAULT_TILE_IMG = self.Tile_Sheet.get_img(self.DEFAULT_TILE_ID)
        map_name = name
        self.width = w
        self.height = h

        for y in range(self.height):
            for x in range(self.width):
                new_tile_background = Tile_.Tile(x,y,self.DEFAULT_TILE_IMG,self.DEFAULT_TILE_ID)
                new_tile_foreground = Tile_.Tile(x,y,None,-1)
                self.MAP["BACKGROUND"]["TILES"].append(new_tile_background)
                self.MAP["FOREGROUND"]["TILES"].append(new_tile_foreground)
        self.save_new(map_name)

        chunks_per_row = int(self.width/self.chunk_size)
        chunks_per_collum = int(self.height/self.chunk_size)

        for y in range(chunks_per_collum):
            for x in range(chunks_per_row):
                pos_x = x*self.tile_size*self.chunk_size
                pos_y = y*self.tile_size*self.chunk_size
                self.MAP["FOREGROUND"]["CHUNKS"].append(Chunk_.Chunk(pos_x,pos_y,self.tile_size,self.chunk_size))
        
        for y in range(chunks_per_collum):
            for x in range(chunks_per_row):
                pos_x = x*self.tile_size*self.chunk_size
                pos_y = y*self.tile_size*self.chunk_size
                self.MAP["BACKGROUND"]["CHUNKS"].append(Chunk_.Chunk(pos_x,pos_y,self.tile_size,self.chunk_size))
    
        for tile in self.MAP["FOREGROUND"]["TILES"]:
            for chunk in self.MAP["FOREGROUND"]["CHUNKS"]:
                if chunk == self.MAP["FOREGROUND"]["CHUNKS"][-1]:#  <----|
                    if chunk.pos_x <= tile.pos_x <= chunk.bound_x:      #|
                        if chunk.pos_y <= tile.pos_y <= chunk.bound_y:  #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                else:                                                   #|
                    if chunk.pos_x <= tile.pos_x < chunk.bound_x:       #|
                        if chunk.pos_y <= tile.pos_y < chunk.bound_y:   #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                                                                        #|
        # I dont know why, but i have to do this ------------------------|   

        for tile in self.MAP["BACKGROUND"]["TILES"]:
            for chunk in self.MAP["BACKGROUND"]["CHUNKS"]:
                if chunk == self.MAP["BACKGROUND"]["CHUNKS"][-1]:#  <----|
                    if chunk.pos_x <= tile.pos_x <= chunk.bound_x:      #|
                        if chunk.pos_y <= tile.pos_y <= chunk.bound_y:  #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                else:                                                   #|
                    if chunk.pos_x <= tile.pos_x < chunk.bound_x:       #|
                        if chunk.pos_y <= tile.pos_y < chunk.bound_y:   #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|

        self.save_new(name)    
        return self.MAP

    def update_img(self):
        self.Image_background = pygame.Surface((self.width*self.tile_size,self.height*self.tile_size))
        for chunk in self.MAP["BACKGROUND"]["CHUNKS"]:
            self.Image_background.blit(chunk.Image,(chunk.pos_x,chunk.pos_y))
        self.Image_foreground = pygame.Surface((self.width*self.tile_size,self.height*self.tile_size))
        for chunk in self.MAP["FOREGROUND"]["CHUNKS"]:
            self.Image_foreground.blit(chunk.Image,(chunk.pos_x,chunk.pos_y))
        self.IMAGE = pygame.Surface((self.width*self.tile_size,self.height*self.tile_size))
        self.IMAGE.blit(self.Image_background,(0,0))
        self.IMAGE.blit(self.Image_foreground,(0,0))
    
    def load_map(self,map_name):
        map_dir = "E:\\Projects\\Python\\Crumbles-Cookie-Adventure\\maps\\"
        path = map_dir + map_name
        with open(path) as file:
            data = json.load(file)
        self.width = data["map_info"]["size_x"]
        self.height = data["map_info"]["size_y"]
        self.map_data = data["map_data"]
        self.map_data_background = data["map_data_background"]

        y_counter = 0
        x_counter = 0
        for row in self.map_data:
            for tile in row:
                pos_x = x_counter*self.tile_size
                pos_y = y_counter*self.tile_size
                new_tile = Tile_.Tile(pos_x,pos_y,self.Tile_Sheet.get_img(tile),int(tile))
                self.MAP["FOREGROUND"]["TILES"].append(new_tile)
                if x_counter*self.tile_size == self.width*self.tile_size:
                    x_counter = 0
                else:
                    x_counter+=1
            if y_counter*self.tile_size == self.height*self.tile_size-1*self.tile_size: # Why this > -1*self.tile_size
                y_counter = 0
            else:
                y_counter+=1

        x_counter = 0
        y_counter = 0
        for row in self.map_data_background:
            for tile in row:
                pos_x = x_counter*self.tile_size
                pos_y = y_counter*self.tile_size
                new_tile = Tile_.Tile(pos_x,pos_y,self.Tile_Sheet.get_img(tile),int(tile))
                self.MAP["BACKGROUND"]["TILES"].append(new_tile)
                if x_counter*self.tile_size == self.width*self.tile_size-1*self.tile_size: # Why this > -1*self.tile_size
                    x_counter = 0
                else:
                    x_counter+=1
            if y_counter*self.tile_size == self.height*self.tile_size:
                y_counter = 0
            else:
                y_counter+=1

        chunks_per_row = int(self.width/self.chunk_size)
        chunks_per_collum = int(self.height/self.chunk_size)

        for y in range(chunks_per_collum):
            for x in range(chunks_per_row):
                pos_x = x*self.tile_size*self.chunk_size
                pos_y = y*self.tile_size*self.chunk_size
                self.MAP["FOREGROUND"]["CHUNKS"].append(Chunk_.Chunk(pos_x,pos_y,self.tile_size,self.chunk_size))
        
        for y in range(chunks_per_collum):
            for x in range(chunks_per_row):
                pos_x = x*self.tile_size*self.chunk_size
                pos_y = y*self.tile_size*self.chunk_size
                self.MAP["BACKGROUND"]["CHUNKS"].append(Chunk_.Chunk(pos_x,pos_y,self.tile_size,self.chunk_size))
    
        for tile in self.MAP["FOREGROUND"]["TILES"]:
            for chunk in self.MAP["FOREGROUND"]["CHUNKS"]:
                if chunk == self.MAP["FOREGROUND"]["CHUNKS"][-1]:#  <----|
                    if chunk.pos_x <= tile.pos_x <= chunk.bound_x:      #|
                        if chunk.pos_y <= tile.pos_y <= chunk.bound_y:  #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                else:                                                   #|
                    if chunk.pos_x <= tile.pos_x < chunk.bound_x:       #|
                        if chunk.pos_y <= tile.pos_y < chunk.bound_y:   #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                                                                        #|
        # I dont know why, but i have to do this ------------------------|   

        for tile in self.MAP["BACKGROUND"]["TILES"]:
            for chunk in self.MAP["BACKGROUND"]["CHUNKS"]:
                if chunk == self.MAP["BACKGROUND"]["CHUNKS"][-1]:#  <----|
                    if chunk.pos_x <= tile.pos_x <= chunk.bound_x:      #|
                        if chunk.pos_y <= tile.pos_y <= chunk.bound_y:  #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
                else:                                                   #|
                    if chunk.pos_x <= tile.pos_x < chunk.bound_x:       #|
                        if chunk.pos_y <= tile.pos_y < chunk.bound_y:   #|
                            chunk.add_tile(tile)                        #|
                            break                                       #|
        # I dont know why, but i have to do this ------------------------| 

        # chunk_tiles = 0        
        # for chunk in self.MAP["FOREGROUND"]["CHUNKS"]:
        #     chunk_tiles+=len(chunk.Tiles)
        
        # print(chunk_tiles)
        # print(len(self.MAP["FOREGROUND"]["TILES"]))

        self.update_img()


    def save_new(self,name):
        dir = "E:\\Projects\\Python\\Crumbles-Cookie-Adventure\\maps\\"
        path = dir + name
        data = {}
        data["map_info"] = {}
        data["map_info"]["size_x"] = self.width
        data["map_info"]["size_y"] = self.height
        data["map_info"]["tilesets"] = [self.Tile_Sheet.sheet_name]
        data["map_data"] = []
        data["map_data_background"] = []

        x_counter = 0
        row = []
        for tile in self.MAP["FOREGROUND"]["TILES"]:
            if x_counter == self.width:
                data["map_data"].append(row)
                row = []
                x_counter = 0
            row.append(tile.get_id())
            if x_counter<=self.width-1:
                x_counter+=1
        data["map_data"].append(row)
        x_counter = 0
        row = []
        for tile in self.MAP["BACKGROUND"]["TILES"]:
            if x_counter == self.width:
                data["map_data_background"].append(row)
                row = []
                x_counter = 0
            row.append(tile.get_id())
            if x_counter<=self.width-1:
                x_counter+=1
        data["map_data_background"].append(row)

        with open(path,"w+") as file:
            json.dump(data,file)
    
    def tick(self):
        for chunk in self.MAP["FOREGROUND"]["CHUNKS"]:
            chunk.tick()
        for chunk in self.MAP["BACKGROUND"]["CHUNKS"]:
            chunk.tick()
        self.update_img()

import pygame

class Chunk:
    def __init__(self,pos_x,pos_y,tsz,size):
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.size = size
        self.tile_size = tsz
        self.Tiles = []

        self.data = {
            (self.pos_x,self.pos_y):self.Tiles
        }

        self.bound_x = pos_x+size*tsz
        self.bound_y = pos_y+size*tsz

        self.Image = pygame.Surface((size*tsz,size*tsz))
    
    def update_image(self):
        for tile in self.Tiles:
            if tile.Image != None:
                scaled_img = pygame.transform.scale(tile.Image,(self.tile_size,self.tile_size))
                self.Image.blit(scaled_img,(tile.pos_x-self.pos_x,tile.pos_y-self.pos_y))

    def tick(self):
        for tile in self.Tiles:
            tile.tick()
        self.update_image()

    def add_tile(self,tile):
        self.Tiles.append(tile)

I've already completly checked my sheet.py file. It just loads the Image for a given tile into memory. Thanks in advance for your help!

EDIT: I've found my error. I did not calculate the position of the tile probably inside the Tile_.py file....

1 Answers

Inside my Tile_.py file, where I init all tiles and assign them to a image, I needed to multiply their position with the tilesize

    def __init__(self,pos_x,pos_y,img,id,tsz,calculate_position=True):
        self.Image = img
        self.id = id
        self.tilesize = tsz
        if calculate_position:
            self.pos_x = pos_x*tsz
            self.pos_y = pos_y*tsz
        else:
            self.pos_x = pos_x
            self.pos_y = pos_y
        self.hitbox = pygame.Rect(self.pos_x,self.pos_y,48,48)
Related