Pygame string-based level draws once then disappears

I'm using Python 2.7. I'm having trouble with redrawing a string-based level. It draws fine for the first frame, but after that, it just doesn't seem to draw anymore. I've been trying to come up with a fix for a while now. Here is the entire source code:

import pygame
from pygame.locals import *

xScan = 0
yScan = 0
level = "WWWWWWWW" \
        "WSSSSSSW" \
        "WSSSSSSW" \
        "WSSSSSSW" \
        "WSSSSSSW" \
        "WWWWWWWW"


class Player():
    def __init__(self, color, x, y, width, height, outline_size):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.outline_size = outline_size

    def draw(self):
        pygame.draw.rect(screen, self.color, [self.x * 80, self.y * 80, self.width * 80, self.height * 80], self.outline_size)


def draw_level():
    for tile in level:
        global xScan, yScan
        if tile == "W":
            pygame.draw.rect(screen, [0, 0, 0], [xScan * 80, yScan * 80, 80, 80], 0)
        elif tile == "S":
            pygame.draw.rect(screen, [120, 120, 120], [xScan * 80, yScan * 80, 80, 80], 1)

        if xScan >= 0 and xScan < 7:
            xScan += 1
        elif xScan == 7:
            xScan = 0
            yScan += 1
        elif yScan == 5 and xScan == 7:
            xScan = 0
            yScan = 0


def update():
    screen.fill([255, 255, 255])
    draw_level()
    player.draw()
    pygame.display.flip()

pygame.init()
screen = pygame.display.set_mode([640, 480])
pygame.display.set_caption("Squares n' Tiles!")
player = Player([0, 100, 255], 1, 1, 1, 1, 0)

running = True
while running:
    clock = pygame.time.Clock()
    clock.tick(30)
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == K_ESCAPE:
                running = False
            if event.key == K_UP and player.y * 80 >= 160:
                player.y -= 1
            if event.key == K_DOWN and player.y * 80 < 320:
                player.y += 1
            if event.key == K_LEFT and player.x * 80 >= 160:
                player.x -= 1
            if event.key == K_RIGHT and player.x * 80 < 480:
                player.x += 1
            if event.key == K_c or event.key == K_r:
                player.x = 1
                player.y = 1
        if event.type == pygame.QUIT:
            running = False
    update()

pygame.quit()

I think the problem lies within this portion of the code:

def draw_level():
    for tile in level:
        global xScan, yScan
        if tile == "W":
            pygame.draw.rect(screen, [0, 0, 0], [xScan * 80, yScan * 80, 80, 80], 0)
        elif tile == "S":
            pygame.draw.rect(screen, [120, 120, 120], [xScan * 80, yScan * 80, 80, 80], 1)

        if xScan >= 0 and xScan < 7:
            xScan += 1
        elif xScan == 7:
            xScan = 0
            yScan += 1
        elif yScan == 5 and xScan == 7:
            xScan = 0
            yScan = 0

I've tried messing with the numbers in the latter half of the previous portion. Here is one variation that mostly fixes the problem (though its format isn't very consistent):

if xScan >= 7:
    xScan = 0
    yScan += 1
elif yScan == 6:
    xScan = 1
    yScan = 0
else:
    xScan += 1

The only problem with the above code is that the top left tile doesn't draw. How could I vary up my code to make it work properly? On every frame, I want the screen to be filled with white, the level re-drawn, the player re-drawn, and the screen flipped. Thanks in advance for any help. I would also appreciate advice on my code's structure.

Answers


The problem is that this block isn't executed:

    elif yScan == 5 and xScan == 7:
        xScan = 0
        yScan = 0

This is because you're looping over each character in the level string, so the max value reached is xScan = 6, yScan = 5.

Instead just initialise xScan and yScan when entering the draw level function

def draw_level():
    xScan = 0 # no need for these to be global
    yScan = 0
    for tile in level:
        if tile == "W":
            pygame.draw.rect(screen, [0, 0, 0], [xScan * 80, yScan * 80, 80, 80], 0)
        elif tile == "S":
            pygame.draw.rect(screen, [120, 120, 120], [xScan * 80, yScan * 80, 80, 80], 1)

        if xScan >= 0 and xScan < 7:
            xScan += 1
        elif xScan == 7:
            xScan = 0
            yScan += 1

I would suggest storing your level as several lines of characters instead of one long string:

level = "WWWWWWWW\n" \
        "WSSSSSSW\n" \
        "WSSSSSSW\n" \
        "WSSSSSSW\n" \
        "WSSSSSSW\n" \
        "WWWWWWWW\n" # note the new line characters (\n)

Then you can iterate over the map like so:

def draw_level():
    for yScan, row in enumerate(level.split('\n')):
        for xScan, tile in enumerate(row):
            if tile == "W":
                pygame.draw.rect(screen, [0, 0, 0], [xScan * 80, yScan * 80, 80, 80], 0)
            elif tile == "S":
                pygame.draw.rect(screen, [120, 120, 120], [xScan * 80, yScan * 80, 80, 80], 1)

enumerate takes a list (or iterable) and returns pairs of (index, item) for each item in the list, for example:

>>> a = 'test'
>>> for i, c in enumerate(a):
...     print('i is {}, c is {}'.format(i, c))
...
i is 0, c is t
i is 1, c is e
i is 2, c is s
i is 3, c is t

Need Your Help

How do I make a genuinely transparent Control?

c# winforms transparency

I need to make a Control which shows only an outline, and I need to place it over a control that's showing a video. If I make my Control transparent, then the video is obscured, because transparent

Editing a string (char array) copying to input string (scanf or fgets.. gets) possible?

c string char edit scanf

I have a question for you, is it possible to the the following in C?

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.