Reputation: 416
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
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
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