[Tutor] Issue With a Python Game

John Bochicchio luckytsukune at gmail.com
Sat Apr 13 15:13:07 CEST 2013


I have a question about a game I am making. I finished the overall code,
but keep getting errors when I try to play. This is my most common error:
C:\Users\John\Documents\Python Games\Noah>python nickeladventuredemo.py
Traceback (most recent call last):
  File "nickeladventuredemo.py", line 451, in <module>
    main()
  File "nickeladventuredemo.py", line 78, in main
    levels = readLevelsFile('levels.txt')
  File "nickeladventuredemo.py", line 371, in readLevelsFile
    assert startx != None  and starty!= None, 'Level %s (around line %s) in
%s i
s missing a "@" or "+" to mark the start point.' % (levelNum+1, lineNum,
filenam
e)
AssertionError: Level 1 (around line 10) in levels.txt is missing a "@" or
"+" t
o mark the start point.

The Code:

import random, sys, copy, os, pygame

from pygame.locals import *



FPS = 30

WINWIDTH = 800

WINHEIGHT = 600

HALF_WINWIDTH = int(WINWIDTH / 2)

HALF_WINHEIGHT = int(WINHEIGHT / 2)



TILEWIDTH = 50

TILEHEIGHT = 85

TILEFLOORHEIGHT = 45



CAM_MOVE_SPEED = 5



OUTSIDE_DECORATION_PCT = 20



BRIGHTBLUE = ( 0, 170, 255)

WHITE      = (255, 255, 255)

BGCOLOR = BRIGHTBLUE

TEXTCOLOR = WHITE



UP = 'up'

DOWN = 'down'

LEFT = 'left'

RIGHT = 'right'





def main():

    global FPSCLOCK, DISPLAYSURF, IMAGESDICT, TILEMAPPING,
OUTSIDECOMAPPING, BASICFONT, PLAYERIMAGES, currentImage



    pygame.init()

    FPSCLOCK = pygame.time.Clock()



    DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))



    pygame.display.set_caption('Noah Nickel Adventure!')

    BASICFONT = pygame.font.Font('freesansbold.ttf', 18)



    IMAGESDICT = {'uncovered goal': pygame.image.load('RedSelector.png'),

                  'covered goal': pygame.image.load('Selector.png'),

                  'star': pygame.image.load('Star.png'),

                  'corner': pygame.image.load('Wall Block Tall.png'),

                  'wall': pygame.image.load('Wood Block Tall.png'),

                  'inside floor': pygame.image.load('Plain Block.png'),

                  'outside floor': pygame.image.load('Grass Block.png'),

                  'title': pygame.image.load('star_title.png'),

                  'solved': pygame.image.load('star_solved.png'),

                  'princess': pygame.image.load('princess.png'),

                  'boy': pygame.image.load('boy.png'),

                  'catgirl': pygame.image.load('catgirl.png'),

                  'horngirl': pygame.image.load('horngirl.png'),

                  'pinkgirl': pygame.image.load('pinkgirl.png'),

                  'rock': pygame.image.load('Rock.png'),

                  'short tree': pygame.image.load('Tree_Short.png'),

                  'tall tree': pygame.image.load('Tree_Tall.png'),

                  'ugly tree': pygame.image.load('Tree_Ugly.png')}



    TILEMAPPING = {'X': IMAGESDICT['corner'],

                   '#': IMAGESDICT['wall'],

                   'o': IMAGESDICT['inside floor'],

                   ' ': IMAGESDICT['outside floor']}



    OUTSIDECOMAPPING = {'1': IMAGESDICT['rock'],

                        '2': IMAGESDICT['short tree'],

                        '3': IMAGESDICT['tall tree'],

                        '4': IMAGESDICT['ugly tree']}

    #Super important to remember:

    #DEAR GOD REMEMBER THIS IS AN INDEX OF PLAYER IMAGES.

    currentImage = 0

    PLAYERIMAGES = [IMAGESDICT['princess'],

                    IMAGESDICT['boy'],

                    IMAGESDICT['catgirl'],

                    IMAGESDICT['horngirl'],

                    IMAGESDICT['pinkgirl']]

    startScreen()



    levels = readLevelsFile('levels.txt')

    currentLevelIndex = 0



    while True:

        result = runLevel(levels, currentLevelIndex)



        if result in ('solved', 'next'):

            currentLevelIndex += 1

            if currentLevelIndex >= len(levels):

                currentLevelIndex = 0



        elif result == 'back':

            currentLevelIndex -= 1

            if currentLevelIndex <0:

                currentLevelIndex = len(levels)-1



        elif result == 'reset':

            pass





def runLevel(levels, levelNum):

    global currentImage

    level0bj = levels[levelnum]

    map0bj = decorateMap(level0bj['map0bj'],
level0bj['startState']['player'])

    gameState0bj = copy.deepcopy(level0bj['startState'])

    mapNeedsRedraw = True

    levelSurf = BASICFONT.render('Level %s of %s' % (level0bj['levelNum']
+1, totalNumOfLevels), 1, TEXTCOLOR)

    levelRect = levelSurf.get_rect()

    levelRect.bottomleft = (20, WINHEIGHT - 35)

    mapWidth = len(map0bj) * TITLEWIDTH

    mapHeight = (len(map0bj[0]) - 1) * (TITLEHEIGHT - TILEFLOORHEIGHT) +
TILEHEIGHT

    MAX_CAM_X_PAN = abs(HALF_WINHEIGHT - int(mapHeight / 2)) + TILEWIDTH

    MAX_CAM_Y_PAN = abs(HALF_WINWIDTH - int(mapWidth / 2)) + TILEHEIGHT



    levelIsComplete = False

    camera0ffsetX = 0

    camera0ffsety = 0

    cameraUp = False

    cameraDown = False

    cameraLeft = False

    cameraRight = False



    while True:

        playerMoveTo = None

        kepPressed = False



        for event in pygame.event.get():

            if event.type == QUIT:

                terminate()



            elif event.type == KEYDOWN:

                keyPressed == True

                if event.key == K_LEFT:

                    playerMoveTo = LEFT

                elif event.key == K_RIGHT:

                    playerMoveTo = RIGHT

                elif event.key == K_UP:

                    playerMoveTo = UP

                elif event.key == K_DOWN:

                    playerMoveTo = DOWN

                elif event.key == K_a:

                    cameraLeft = True

                elif event.key == K_d:

                    cameraRight = True

                elif event.key == K_w:

                    cameraUp = True

                elif event.key == K_s:

                    cameraDown = True



                elif event.key == K_n:

                    return 'next'

                elif event.key == K_b:

                    return 'back'



                elif event.key == K_ESCAPE:

                    terminate() #Perhaps add a print box confirmation?

                elif event.key == K_BACKSPACE:

                    return 'reset' #Same confirmation for level reset.

                elif event.key == K_p:

                    currentImage += 1

                    if currentImage >= len(PLAYERIMAGES):

                        currentImage = 0

                        mapNeedsRedraw = True

                elif event.type == KEYUP:

                    if event.key == K_a:

                        cameraLeft = False

                    elif event.key == K_d:

                        cameraRight = False

                    elif event.key == K_w:

                        cameraUp = False

                    elif event.key == K_s:

                        cameraDown = False



                if playerMoveTo != None and not levelIsComplete:

                    moved = makeMove(map0bj, gameState0bj, playerMoveTo)



                    if moved:

                        gameState0bj['stepCounter'] += 1

                        mapNeedsRedraw = True



                    if isLevelFinished(level0bj, gameState0bj):

                        levelIsComplete = True

                        keyPressed = False



                DISPLAYSURF.fill(BGCOLOR)



                if mapNeedsRedraw:

                    mapSurf = drawMap(map0bj, gameState0bj,
level0bj['goals'])

                    mapNeedsRedraw = False



                if cameraUp and camera0ffsetY < MAX_CAM_X_PAN:

                    camera0ffsetY += CAM_MOVE_SPEED

                elif cameraDown and camera0ffsetY > -MAX_CAM_X_PAN:

                    camera0ffsetY -= CAM_MOVE_SPEED

                if cameraLeft and camera0ffsetX < MAX_CAM_Y_PAN:

                    camera0ffsetX += CAM_MOVE_SPEED

                elif cameraRight and camera0ffsetX > -MAX_CAM_Y_PAN:

                    camera0ffsetX -= CAM_MOVE_SPEED



                mapSurfRect = mapSurf.get_rect()

                mapSurfRect.center = (HALF_WINWIDTH + camera0ffsetX,
HALF_WINHEIGHT + camera0ffsetY)



                DISPLAYSURF.blit(mapSurf, levelRect)

                stepSurf = BASICFONT.render('Steps: %s'
%(gameState0bj['stepCounter']), 1, TEXTCOLOR)

                stepRect = stepSurf.get_rect()

                stepRect.bottomleft = (20, WINHEIGHT -10)

                DISPLAYSURF.blit(stepSurf, stepRect)



                if levelIsComplete:

                    solvedRect = IMAGESDICT['solved'].get_rect()

                    dolvedRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)

                    DISPLAYSURF.blit(IMAGESDICT['solved'], solvedRect)



                if keyPressed:

                    return 'solved'



                pygame.display.update()

                FPSCLOCK.tick()





def decorateMap(map0bj, startxy):



    startx, starty = startxy



    map0bjCopy = copy.deepcopy(map0bj)



    for x in range(len(map0bjCopy)):

        for y in range(len(map0bjCopy[0])):

            if map0bjCopy[x][y] in ('$', '.', '@', '+', '*'):

                map0bjCopy[x][y] = ' '



    floodFill(map0bjCopy, startx, starty, ' ', 'o')



    for x in range(len(map0bjCopy)):

        for y in range(len(map0bjCopy[0])):



            if (isWall(mapObjCopy, x, y-1) and isWall(mapObjCopy, x+1, y))
or \

               (isWall(mapObjCopy, x+1, y) and isWall(mapObjCopy, x, y+1))
or \

               (isWall(mapObjCopy, x, y+1) and isWall(mapObjCopy, x-1, y))
or \

               (isWall(mapObjCopy, x-1, y) and isWall(mapObjCopy, x, y-1)):

                map0bjCopy[x][y] = 'x'



            elif map0bjCopy[x][y] == ' ' and random.randint(0, 99) <
OUTSIDE_DECORATION_PCT:

                 map0bjCopy[x][y] =
random.choice(list(OUTSIDECOMAPPING.keys()))



    return map0bjCopy





def isBlocked(map0bj, gameState0bj, x, y):



    if isWall(map0bj, x, y):

        return True



    elif x < 0 or x >= len(map0bj) or y < 0 or y >= len(map0bj[x]):

        return True



    return False



def makeMove(map0bj, gameState0bj, playerMoveTo):

    playerx, playery = gameState0bj['player']



    stars = gameState0bj['stars']



    if playerMoveTo == UP:

        x0ffset = 0

        y0ffset = -1

    elif playerMoveTo == RIGHT:

        x0ffset = 1

        y0ffset = 0

    elif playerMoveTo == DOWN:

        x0ffset = 0

        y0ffset = 1

    elif playerMoveTo == LEFT:

        x0ffset = -1

        y0ffset = 0



    if isWall(map0bj, playerx, x0ffset, playery + y0ffset):

        return False

    else:

        if (playerx + x0ffset, playery + y0ffset) in stars:

            if not isBlocked(map0bj, gameState0bj, playerx + (x0ffset*2),
playery + (y0ffset*2)):

                ind = stars.index((playerx + x0ffset, playery + y0ffset))

                stars[ind] = (stars[ind][0] + x0ffset, stars[ind][1] +
y0ffset)

            else:

                return False



        gameState0bj['player'] = (playerx + x0ffset, playery + y0ffset)

        return True





def startScreen():



    titleRect = IMAGESDICT['title'].get_rect()

    topCoord = 50

    titleRect.top = topCoord

    titleRect.centerx = HALF_WINWIDTH

    topCoord += titleRect.height



    instructionText = ['Push the stars over the marks.',

                       'Arrow keys move the player, WASD controls the
camera, and P changes the characer.',

                       'Backspaced resets the level, Escape quits the
game.',

                       'N for next level, B to go back a level.']



    DISPLAYSURF.fill(BGCOLOR)



    DISPLAYSURF.blit(IMAGESDICT['title'], titleRect)



    for i in range(len(instructionText)):

        instSurf = BASICFONT.render(instructionText[i], 1, TEXTCOLOR)

        instRect = instSurf.get_rect()

        topCoord += 10

        instRect.top = topCoord

        instRect.centerx = HALF_WINWIDTH

        topCoord += instRect.height

        DISPLAYSURF.blit(instSurf, instRect)



    while True:

        for event in pygame.event.get():

            if event.type == QUIT:

                terminate()

            elif event.type == KEYDOWN:

                if event.key ==K_ESCAPE:

                    terminate()

                return



        pygame.display.update()

        FPSCLOCK.tick()





def readLevelsFile(filename):

    assert os.path.exists(filename), 'Cannot find the level file: %s' %
(filename)

    mapFile = open(filename, 'r')

    content = mapFile.readlines() + ['\r\n']

    mapFile.close()



    levels = []

    levelNum = 0

    mapTextLines = []

    map0bj = []

    for lineNum in range (len(content)):

        line = content[lineNum].rstrip('\r\n')



        if ';' in line:

            line = line[:line.find(';')]

        if line != '':

            mapTextLines.append(line)

        elif line == '' and len(mapTextLines) > 0:



            maxWidth = -1

            for i in range(len(mapTextLines)):

                if len(mapTextLines[i]) > maxWidth:

                    maxWidth = len(mapTextLines[i])



            for i in range(len(mapTextLines)):

                mapTextLines[i] += ' ' * (maxWidth - len(mapTextLines[i]))



            for x in range(len(mapTextLines[0])):

                map0bj.append([])

            for y in range(len(mapTextLines)):

                for x in range(maxWidth):

                    map0bj[x].append(mapTextLines[y][x])



            startx = None

            starty = None

            goals = []

            stars = []

            for x in range(maxWidth):

                for y in range (len(map0bj[x])):

                    if map0bj[x][y] in ('@', '+'):

                        startx = x

                        starty = y

                    if map0bj [x][y] in ('.', '+', '*'):

                        goals.append((x, y))

                assert startx != None  and starty!= None, 'Level %s (around
line %s) in %s is missing a "@" or "+" to mark the start point.' %
(levelNum+1, lineNum, filename)

                assert len(goals) > 0, 'Level %s (around line %s) in %s
must have at least one goal.' % (levelNum+1, lineNum, filename)

                assert len(stars) >= len(goals), 'Level %s (around line %s)
in %s is impossible to solve. It has %s goals but only %s stars.' %
(levelNum+1, lineNum, filename, len(goals), len(stars))



                gameState0bj = {'player': (startx, starty),

                                'stepCounter': 0,

                                'stars': stars}

                level0bj = {'width': maxWidth,

                            'height': len(map0bj),

                            'map0bj': map0bj,

                            'goals': goals,

                            'startState': gameState0bj}



                levels.append(level0bj)



                mapTextLines = []

                map0bj = []

                gameState0bj = {}

                levelNum += 1

    return levels





def floodFill(map0bj, x, y, oldCharacter, newCharacter):

    if map0bj[x][y] == oldCharacter:

        map0bj[x][y] = newCharacter



    if x < len(map0bj) - 1 and map0bj[x+1][y] == oldCharacter:

        floodFill(map0bj, x+1, y, oldCharacter, newCharacter)

    if x > 0 and map0bj[x-1][y] == oldCharacter:

        floodFill(mapObj, x-1, y, oldCharacter, newCharacter)

    if y < len(mapObj[x]) - 1 and mapObj[x][y+1] == oldCharacter:

        floodFill(mapObj, x, y+1, oldCharacter, newCharacter)

    if y > 0 and mapObj[x][y-1] == oldCharacter:

        floodFill(mapObj, x, y-1, oldCharacter, newCharacter)





def drawMap(map0bj, gamestate0bj, goals):

    mapSurfWidth = len(map0bj) * TILEWIDTH

    mapSurfHeight = len(len(map0bj[0]) - 1) * (TILEHEIGHT -
TILEFLOORHEIGHT) + TILEHEIGHT

    mapSurf = pygame.Surface((mapSurfWidth, mapSurfHeight))

    mapSurf.fill(BGCOLOR)



    for x in range(len(map0bj)):

        for y in range(len(map0bj)):

            spaceRect = pygame.Rect((x * TILEWIDTH, y * (TILEHEIGHT -
TILEFLOORHEIGHT), TILEWIDTH, TILEHEIGHT))

            if map0bj[x][y] in TILEMAPPING:

                baseTile = TILEMAPPING[map0bj[x][y]]

            elif map0bj[x][y] in OUTSIDECOMAPPING:

                baseTile = TILEMAPPING[' ']



            mapSurf.blit(baseTile, spaceRect)



            if map0bj[x][y] in OUTSIDECOMAPPING:

                mapSurf.blit(OUTSIDEDECOMAPPING[map0bj[x][y]], spaceRect)

            elif (x, y) in gameState0bj['stars']:

                if (x, y) in goals:

                    mapSurf.blit(IMAGESDICT['covered goal'], spaceRect)

                mapSurf.blit(IMAGESDICT['star'], spaceRect)

            elif (x, y) in goals:

                mapSurf.blit(IMAGESDICT['uncovered goal'], spaceRect)



            if (x, y) == gameState0bj['player']:

                mapSurf.blit(PLAYERIMAGES[currentImage], spaceRect)



    return mapSurf





def isLevelFinished(level0bj, gameState0bj):

    for goal in level0bj['goals']:

        if goal not in gameState0bj['stars']:

            return False

    return True





def terminate():

    pygame.quit()

    sys.exit()





if __name__ == '__main__':

    main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/tutor/attachments/20130413/e8c4b2be/attachment-0001.html>


More information about the Tutor mailing list