Ryan
Ryan

Reputation: 416

Tile based game using pygame questions / problems

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!"

Upvotes: 2

Views: 3638

Answers (2)

sloth
sloth

Reputation: 101052

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

Upvotes: 1

Marius
Marius

Reputation: 60060

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))

Upvotes: 1

Related Questions