I'm following a tutorial for making tiled maps in pygame and on the very first piece of code I'm getting an error. ()

On this line "for tile_x in range(0, image_width/width):" it's raising this error: "'float' object cannot be interpreted as an integer". The image dimensions I'm loading are 96x64.

Here's the code, any help would be great.

import pygame, sys
from pygame.locals import *

#load tiles into memory and slice into single tiles
def load_tile_table(filename, width, height):
    image = pygame.image.load(filename).convert_alpha()
    image_width, image_height = image.get_size()
    tile_table = []
    for tile_x in range(0, image_width/width):
        line = []
        tile_table.append(line)
        for tile_y in range(0, image_height/height):
            rect = (tile_x*width, tile_y*height, width, height)
            line.append(image.subsurface(rect))
    return tile_table

def main():
    pygame.init()
    screen = pygame.display.set_mode((128,98))
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
        screen.fill((255,255,255))
        table = load_tile_table("ground.png", 24, 16)
        for x, row in enumerate(table):
            for y, tile in enumerate(row):
                screen.blit(tile, (x*32, y*24))
        pygame.display.update()

main()

Dani AI

Generated

The error occurs because range must receive integers. A robust way to compute the number of columns/rows of tiles is to derive them as integers up-front and also verify the image dimensions are evenly divisible by the tile size. Using divmod makes this explicit and helps you fail fast if the sprite sheet is mis-sized. Also note that Surface.subsurface shares pixel data with the original image; call .copy() if you want independent surfaces you can modify safely.

def load_tiles(filename, tile_w, tile_h, copy=False):
    img = pygame.image.load(filename).convert_alpha()
    img_w, img_h = img.get_size()
    cols, rem_w = divmod(img_w, tile_w)
    rows, rem_h = divmod(img_h, tile_h)
    if rem_w or rem_h:
        raise ValueError("Tile size does not evenly divide image size")

    tiles = []
    for y in range(rows):
        row = []
        for x in range(cols):
            rect = pygame.Rect(x*tile_w, y*tile_h, tile_w, tile_h)
            tile = img.subsurface(rect)
            row.append(tile.copy() if copy else tile)
        tiles.append(row)
    return tiles

When drawing, multiply indices by the actual tile width/height so tiles align without gaps or overlap, and size the window accordingly:

tiles = load_tiles("ground.png", 24, 16)
screen = pygame.display.set_mode((len(tiles[0])*24, len(tiles)*16))
for y, row in enumerate(tiles):
    for x, t in enumerate(row):
        screen.blit(t, (x*24, y*16))

Python’s range type is documented at docs.python.org; divmod is described at docs.python.org. See Pygame’s docs for Surface.subsurface and convert_alpha behavior.

Recommended Answers

All 2 Replies

range value should be integer:

for tile_x in range(0, int(image_width/width)):

In Python 2 the / operator returns an integer if both operands are integers - rounding the result down if necessary. So 3/2 would be 1 in Python 2. In Python 3 this behavior has been changed, so that / always returns a float even if both operands are integers. So 3/2 would be 1.5 and 4/2 would be 2.0.

The code you've posted was apparently written for Python 2 where image_width/width would result in an integer. Presumably you're using Python 3 where it results in a float and that's why you get that error. To fix this you can replace the / operator with the // operator, which performs integer division (in both Python 2 and Python 3).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.