2

Thanks for taking the time to read this. I am trying to create a very basic tile game system with pygame. I am not the best at pygame, so I may be missing something fairly obvious. So far I have everything in one file. What I have right now seems really sloppy and there is probably a more efficient way of doing it, but right now I am just using 2d Arrays with a number that equates to a specific type of tile, (grass, water, etc). For that I am using numpy because that is what someone recommended to me. Though I don't know if I like this method, because what if in the future I had some tile that was not simply graphical, and had more specific attributes to it? Like a treasure chest for example or a trap? How would you structure this?

But none the less, my problem is right now the screen is simply black, and isn't drawing the grass tiles.

Here is the code:

import numpy
import pygame
import sys
from pygame.locals import *

pygame.init()

fpsClock = pygame.time.Clock()

windowWi = 800
windowHi = 608

mapWi = 50 # *16 = 800, etc
mapHi = 38

# ----- all of the images ------------------------------

grass1 = pygame.image.load('pictures\(Grass\grass1.png')


#-------------------------------------------------------
screen = pygame.display.set_mode((windowWi, windowHi))
pygame.display.set_caption("Tile Testing!")

gameRunning = True

groundArray = numpy.ones((mapWi,mapHi))

def drawMapArray(maparray):
    for x in range(mapWi,1):
        for y in range(mapHi,1):
            #Determines tile type.
            if maparray[y,x] == 1:
                screen.blit(grass1, (x*16, y*16))
            else:
                print "Nothing is here!"

while gameRunning:
    drawMapArray(groundArray)

    for event in pygame.event.get():
        if event.type == "QUIT":
            pygame.quit()
            sys.exit()



    #Updates display and then sets FPS to 30 FPS. 
    pygame.display.update()
    fpsClock.tick(30)

Please feel free to steer me in a better structural direction as I am very new to game design and want any feedback!

Thanks, Ryan

EDIT: I have tried this, which makes sense logically but I am getting an index out of range error.

def drawMapArray(maparray):
    for x in range(0,mapWi,1):
        for y in range(0,mapHi,1):
            #Determines tile type.
            if maparray[y,x] == 1:
                screen.blit(grass1, (x*16, y*16))
            else:
                print "Nothing is here!"
10
  • 1
    Do you mean to have a "(" in the file name pictures\(Grass\grass1.png ? Commented Aug 9, 2012 at 0:02
  • I think your range() calls might be the wrong way around, try for x in range(1, mapWi):. Commented Aug 9, 2012 at 0:04
  • Thats how the file was named haha, these were just some open source 16bit tile images that I was using for testing purposes. I will change it soon because it is confusing looking. Commented Aug 9, 2012 at 0:07
  • But whenever I seem to change the range() calls I get index out of bound errors. Commented Aug 9, 2012 at 0:09
  • 1
    I mean people will probably, not please will probably of course :-) Commented Aug 9, 2012 at 13:32

2 Answers 2

1

One solution that might scale better as you add more tile types is using a dictionary to get from the numbers in your array to the images, e.g.:

tile_dict = {1 : pygame.image.load('pictures\(Grass\grass1.png'),
             2 : pygame.image.load('pictures\rock.png')
            }

And then just draw the relevant entry from the dictionary in your draw function

def drawMapArray(maparray):
    for x in range(0, mapWi):
        for y in range(0, mapHi):
            #Determines tile type.
            current_tile = tile_dict[maparray[x, y]]
            screen.blit(current_tile, (x*16, y*16))
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! This is much cleaner then what I have and will save me from writing too many if else statements. What do you suggest though if I have tiles that represent something more complex, like a chest with items in it, or tiles a player couldn't move through? Can I do that within the scope of this method or would I have to move onto something like a Tile class?
Yes, once you start adding that kind of complex behaviour, you might have to start thinking about classes. If you're comfortable with operator overloading, you might want to think about creating your own array class that implements the map as a list of lists, and supports [x, y] indexing by overloading __getitem__. That would allow you to store your own classes/datatypes in the array, rather than numbers.
1

Your draw method is wrong.

def drawMapArray(maparray):
    for x in range(mapWi,1):
        for y in range(mapHi,1):
            #Determines tile type.
            if maparray[y,x] == 1:
                screen.blit(grass1, (x*16, y*16))

The first error is for x in range(mapWi,1).

Have a look at the range function. You're using two parameters, so you loop from mapWi to 1, which is not what you want.

You want to loop from 0 to mapWi, so you have to use

for x in range(mapWi):
    for y in range(mapHi):

(using xrange would be even better, but that would be just a very minor improvement)

Otherwise, nothing will be drawn on the screen.


The second error is this line:

if maparray[y,x] == 1:

You'll get an IndexError because you mixed up the initialization of the array. It's actually mapWi high and mapHi wide. So, you should initalize it using

groundArray = numpy.ones((mapHi,mapWi))

instead of

groundArray = numpy.ones((mapWi,mapHi))

To illustrate it, just a little test:

>>> numpy.ones((10,5))
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])
>>>

You'll see that using (10, 5) gives us an array of height = 10 and width = 5.


Sidenotes:

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

will do nothing. event.type is never a string "QUIT". The type of the quit event is 12, or better: pygame.QUIT; so it should read:

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

Rewrite your mainloop like this:

while gameRunning:
    drawMapArray(groundArray)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameRunning = False
            break

    #Updates display and then sets FPS to 30 FPS. 
    pygame.display.update()
    fpsClock.tick(30)

pygame.quit()

to avoid calling sys.exit.

Better: split your main loop into the three steps you usually do in a mainloop.

while gameRunning:
    draw()         # do all the drawing stuff in this function
    handle_input() # handle all input stuff in this function
    update()       # update the game state in this function

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.