I'm trying to add walls when a player gets to a certain score however the wall doesn't draw correctly

Question:

I am trying to add one of my walls when the player hits a score of 10. The desired behaviour would be for the wall to stay after the score requirement is complete. I have tried a few different ways, first I tried to do a simple if statement the issue is the wall doesn’t draw I added a display update and it just flickers I assumed because it was constantly updating where the statement is true so I added

run_once = 0
   while True: # main game loop
       if run_once == 0 and score >= 10:
           run_once = 1
           drawWall(wallCoords)
           pygame.display.update()

this makes the wall spawn and go away I needed to add my hit logic to the statement however don’t want that to run once so I did a elif with the hit logic

elif run_once == 1:
            #check if worm hit a wall(one for each block in wall)
            if wormCoords[HEAD]['x'] == wallCoords[0]['x'] and wormCoords[HEAD]['y'] == wallCoords[0]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[0]['x'] and wormCoords[HEAD]['y'] == wallCoords2[0]:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            if wormCoords[HEAD]['x'] == wallCoords[1]['x'] and wormCoords[HEAD]['y'] == wallCoords[1]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[1]['x'] and wormCoords[HEAD]['y'] == wallCoords2[1]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            if wormCoords[HEAD]['x'] == wallCoords[2]['x'] and wormCoords[HEAD]['y'] == wallCoords[2]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[2]['x'] and wormCoords[HEAD]['y'] == wallCoords2[2]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            if wormCoords[HEAD]['x'] == wallCoords2[3]['x'] and wormCoords[HEAD]['y'] == wallCoords2[3]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return
            if wormCoords[HEAD]['x'] == wallCoords2[4]['x'] and wormCoords[HEAD]['y'] == wallCoords2[4]['y']:
                high_score = score
                set_high_score(HIGH_SCORE_FILE, player_name, high_score)
                return

what could I do differently? Here is a minimal version of the full code

import random, pygame, sys, time, pickle, os
from pygame.locals import *
from operator import itemgetter

FPS = 15
EASYFPS = 12
HARDFPS = 25
INSANEFPS = 35
drawHighApple = 10
drawSuperHighApple = 40
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
CELLSIZE = 20
assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
#               R    G    B
WHITE       = (255, 255, 255)
BLACK       = ( 0,    0,   0)
RED         = (255,   0,   0)
YELLOW      = (255, 255,   0)
GREEN       = (  0, 255,   0)
GRAY        = (185, 185, 185)
BLUE        = (  0,   0, 255)
NAVYBLUE    = ( 60,  60, 100)
ORANGE      = (255, 128,   0)
PURPLE      = (170,   0, 255)
CYAN        = (  0, 255, 255)
LIGHTRED    = (175,  20,  20)
LIGHTGREEN  = ( 20, 175,  20)
LIGHTBLUE   = ( 20,  20, 175)
LIGHTYELLOW = (175, 175,  20)
BRIGHTBLUE  = (  0,  50, 255)
DARKGREEN   = (  0, 155,   0)
DARKGRAY    = ( 40,  40,  40)
BGCOLOR = BLACK

UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'

HEAD = 0

def main():
    noSelection = True
    
    global FPSCLOCK, DISPLAYSURF, BASICFONT, EASY_SURF, EASY_RECT, NORMAL_SURF, NORMAL_RECT, HARD_SURF, HARD_RECT, INSANE_SURF, INSANE_RECT

    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
    BASICFONT = pygame.font.Font('freesansbold.ttf', 18)

    pygame.display.set_caption('Worms')

    showStartScreen()
    mousex = 0
    mousey = 0
    
    while True:
        noSelection = True
        for event in pygame.event.get():
            if event.type == MOUSEBUTTONUP:
                mousex, mousey = event.pos
                
        if noSelection == True:
            runGame()
            showGameOverScreen()
def runGame():
    # Sets a random start point.
    # Sets a random start point.
    startx = random.randint(5, CELLWIDTH - 6)
    starty = random.randint(5, CELLHEIGHT - 6)
    wallsx = int(19)
    wallsy = int(12)
    wallsx2 = int(9)
    wallsy2 = int(10)
    wormCoords = [{'x': startx,     'y': starty},
                  {'x': startx - 1, 'y':  starty},
                  {'x': startx - 2, 'y': starty}]
    direction = RIGHT
    wallCoords = [{'x': wallsx,      'y': wallsy},
                  {'x': wallsx,      'y': wallsy + 1},
                  {'x': wallsx,      'y': wallsy + 2}]
    wallCoords2 = [{'x': wallsx2,    'y': wallsy2 },
                   {'x': wallsx2,    'y': wallsy2 + 1},
                   {'x': wallsx2,    'y': wallsy2 + 2},
                   {'x': wallsx2 + 1, 'y': wallsy2 },
                   {'x': wallsx2 + 1, 'y': wallsy2 + 2 }]

    # Start the apple in a random place.
    apple = getRandomLocation()
    highValueApple = getRandomLocation()
    superHighValueApple = getRandomLocation()

    lastHighValueApple = time.time()
    lastSuperHighApple = time.time()

    score = 0
    run_once = 0
    while True: # main game loop
        if run_once == 0 and score >= 10:
            run_once = 1
            drawWall(wallCoords)
            pygame.display.update()
        elif run_once == 1:
            #check if worm hit a wall(one for each block in wall)
            if wormCoords[HEAD]['x'] == wallCoords[0]['x'] and wormCoords[HEAD]['y'] == wallCoords[0]['y']:
                high_score = score
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[0]['x'] and wormCoords[HEAD]['y'] == wallCoords2[0]:
                high_score = score
                return
            if wormCoords[HEAD]['x'] == wallCoords[1]['x'] and wormCoords[HEAD]['y'] == wallCoords[1]['y']:
                high_score = score
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[1]['x'] and wormCoords[HEAD]['y'] == wallCoords2[1]['y']:
                high_score = score
                return
            if wormCoords[HEAD]['x'] == wallCoords[2]['x'] and wormCoords[HEAD]['y'] == wallCoords[2]['y']:
                high_score = score
                return
            elif wormCoords[HEAD]['x'] == wallCoords2[2]['x'] and wormCoords[HEAD]['y'] == wallCoords2[2]['y']:
                high_score = score
                return
            if wormCoords[HEAD]['x'] == wallCoords2[3]['x'] and wormCoords[HEAD]['y'] == wallCoords2[3]['y']:
                high_score = score
                return
            if wormCoords[HEAD]['x'] == wallCoords2[4]['x'] and wormCoords[HEAD]['y'] == wallCoords2[4]['y']:
                high_score = score
                return

        if highValueApple == False:
            # No high value apple
            highValueApple = getRandomLocation()
            lastHighValueApple = time.time()
        elif superHighValueApple == False:
            #No super high value apple
            superHighValueApple = getRandomLocation()
            lastSuperHighApple = time.time()
            
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
                    direction = LEFT
                elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
                    direction = RIGHT
                elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
                    direction = UP
                elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
                    direction = DOWN
                elif event.key == K_ESCAPE:
                    terminate()


        # check if the worm has hit itsself or the edge
        if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
            return
        for wormBody in wormCoords[1:]:
            if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
                return
        # check if worm has eaten an apply
        if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
            # don't remove worms tal segment
            score += 1
            apple = getRandomLocation()
        elif wormCoords[HEAD]['x']  == highValueApple['x'] and wormCoords[HEAD]['y'] == highValueApple['y']:
            lastHighValueApple = time.time() # Resets lastHighValueApple  (IMPORTANT if you want to keep the draw delay after eating an apple)
            score += 2
            highValueApple = getRandomLocation()
        elif wormCoords[HEAD]['x'] == superHighValueApple['x'] and wormCoords[HEAD]['y'] == superHighValueApple['y']:
            lastSuperHighApple = time.time() #resets lastSuperHighApple  (IMPORTANT if you want to keep the draw delay after eating an apple)
            score += 5
            superHighValueApple = getRandomLocation()
        else:
            del wormCoords[-1] # remove worms tail segment

                # move the worm by adding segment in direction it is moving
        if direction == UP:
            newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
        elif direction == DOWN:
            newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
        elif direction == LEFT:
            newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
        elif direction == RIGHT:
            newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
        wormCoords.insert(0, newHead)
        DISPLAYSURF.fill(BGCOLOR)
        drawGrid()
        drawWorm(wormCoords)
        if time.time() - lastHighValueApple > drawHighApple:
            drawHighValueApple(highValueApple)
        drawApple(apple)
        if time.time() - lastSuperHighApple > drawSuperHighApple:
            drawSuperHighValueApple(superHighValueApple)
        drawScore(score)
        pygame.display.update()
        FPSCLOCK.tick(FPS)

def drawPressKeyMsg():
    pressKeySurf = BASICFONT.render('Press a Key to play.', True, DARKGRAY)
    pressKeyRect = pressKeySurf.get_rect()
    pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
    DISPLAYSURF.blit(pressKeySurf, pressKeyRect)


def checkForKeyPress():
    if len(pygame.event.get(QUIT)) > 0:
        terminate()

    keyUpEvents = pygame.event.get(KEYUP)
    if len(keyUpEvents) == 0:
        return None
    if keyUpEvents[0].key == K_ESCAPE:
        terminate()
    return keyUpEvents[0].key


def showStartScreen():
    titleFont = pygame.font.Font('freesansbold.ttf', 100)
    titleSurf1 = titleFont.render('Wormy!', True, WHITE, DARKGREEN)
    titleSurf2 = titleFont.render('Wormy!', True, GREEN)

    degrees1 = 0
    degrees2 = 0
    while True:
        DISPLAYSURF.fill(BGCOLOR)
        rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
        rotatedRect1 = rotatedSurf1.get_rect()
        rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
        DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)

        rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
        rotatedRect2 = rotatedSurf2.get_rect()
        rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
        DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)

        drawPressKeyMsg()

        if checkForKeyPress():
            pygame.event.get() #clear event que
            return
        pygame.display.update()
        FPSCLOCK.tick(FPS)
        degrees1 += 3
        degrees2 += 7


def terminate():
    pygame.quit()
    sys.exit()


def getRandomLocation():
    return {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0,
CELLHEIGHT - 1)}


def showGameOverScreen():
    gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
    gameSurf = gameOverFont.render('Game', True, WHITE)
    overSurf = gameOverFont.render('Over', True, WHITE)
    gameRect = gameSurf.get_rect()
    overRect = overSurf.get_rect()
    gameRect.midtop = (WINDOWWIDTH / 2, 10)
    overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)

    DISPLAYSURF.blit(gameSurf, gameRect)
    DISPLAYSURF.blit(overSurf, overRect)
    drawPressKeyMsg()
    pygame.display.update()
    pygame.time.wait(500)
    checkForKeyPress()

    while True:
        if checkForKeyPress():
            pygame.event.get() # clear event queue
            return

def drawScore(score):
    scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
    scoreRect = scoreSurf.get_rect()
    scoreRect.topleft = (WINDOWWIDTH - 120, 10)
    DISPLAYSURF.blit(scoreSurf, scoreRect)


def drawWorm(wormCoords):
    for coord in wormCoords:
        x = coord['x'] * CELLSIZE
        y = coord['y'] * CELLSIZE
        wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
        pygame.draw.rect(DISPLAYSURF, GREEN, wormSegmentRect)
        wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
        pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)

def drawWall(wallCoords):
    for coord in wallCoords:
        x = coord['x'] * CELLSIZE
        y = coord['y'] * CELLSIZE
        wallSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
        pygame.draw.rect(DISPLAYSURF, BLUE, wallSegmentRect)
        wallInnerRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
        pygame.draw.rect(DISPLAYSURF, BLUE, wallInnerRect)

def drawWall2(wallCoords):
    for coord in wallCoords:
        x = coord['x'] * CELLSIZE
        y = coord['y'] * CELLSIZE
        wallSegmentRect2 = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
        pygame.draw.rect(DISPLAYSURF, GREEN, wallSegmentRect2)
        wallInnerRect2 = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
        pygame.draw.rect(DISPLAYSURF, GREEN, wallInnerRect2)

def drawApple(coord):
    x = coord['x'] * CELLSIZE
    y = coord['y'] * CELLSIZE
    appleRect = (x, y, CELLSIZE, CELLSIZE)
    pygame.draw.rect(DISPLAYSURF, RED, appleRect)


def drawHighValueApple(coord):
    x = coord['x'] * CELLSIZE
    y = coord['y'] * CELLSIZE
    highValueAppleRect = (x, y, CELLSIZE, CELLSIZE)
    pygame.draw.rect(DISPLAYSURF, GREEN, highValueAppleRect)
    highValueInnerAppleRect = pygame.Rect(x + 2, y + 2, CELLSIZE - 10, CELLSIZE - 10)
    pygame.draw.rect(DISPLAYSURF, RED, highValueInnerAppleRect)


def drawSuperHighValueApple(coord):
    x = coord['x'] * CELLSIZE
    y = coord['y'] * CELLSIZE
    superHighValueAppleRect = (x, y, CELLSIZE, CELLSIZE)
    pygame.draw.rect(DISPLAYSURF, CYAN, superHighValueAppleRect)
    superHighValueInnerAppleRect = pygame.Rect(x + 3, y + 3, CELLSIZE - 10, CELLSIZE - 10)
    pygame.draw.rect(DISPLAYSURF, LIGHTGREEN, superHighValueInnerAppleRect)


def drawGrid():
    for x in range(0, WINDOWWIDTH, CELLSIZE):
        pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
    for y in range(0, WINDOWHEIGHT, CELLSIZE):
        pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))


if __name__ == '__main__':
    main()
        

Answers:

You can do it diffrent ways :

  1. First you can use a global boolean variable -> show_walls = False Your wall can exist since the beggining but you only draw them and only check for collision when "show_walls" is True. You set it to True when the score reach 10. Then just never set it back to False, they will stay up like you wish.

  2. As other suggested you can put your walls in a list (which you should honestly, if anything it will simplify you code). You add your walls to the list when the score reach 10, has long as you dont remove them from the list, they will be here.


The problem with your code is your condition before the DrawWall

if run_once == 0 and score >= 10:
    run_once = 1
    drawWall(wallCoords)

Think about it, when your score, is > or = to 10, you will enter your condition and run_once will be set to 1 so you will never enter this condition again. But you draw your wall inside this if condition. So you will only draw your wall for one frame.


Besides that, there are plenty of concerning points in your code :

  • There is no reason for your walls to be list of dictionnaries. You are using pygame : why don’t you just use pygame.Rect() to represent your walls ?
  • The fact that you are using FPS as a way to change the speed for different difficulties. You should use a speed variable. What you are doing is making the game laggy to slow the speed down.
  • The fact that you have multiple functions to do the same exact thing :
    For instance DrawWall(...) and DrawWall2(...)
    Yes, I know one draws wall 1 and the other draws wall 2. But just make one function that takes every information about the wall as input and the draw it based on the passed values. Here is an example, obviously the function in my example is pointless but this is just to illustrate what you are doing.
  • # This is what you are doing :
    
    def print_text1():
        print(text1)
    
    def print_text2():
        print(text2)
    
    text1 = "foo"
    text2 = "bar"
    
    print_text1(text1)
    print_text2(text2)
    
    # This is what you should do :
    def print_text(text):
        print(text)
    
    text1 = "foo"
    text2 = "bar"
    
    print_text(text1)
    print_text(text2)
    
    

    Now you could just add as many "text…" variables as you wish, you don’t need to write a new function everytime. This may seem obvious here but that is exactly what you are doing with drawWall(…) and drawWall2(…). Here you have two walls, but what if you had 50 ? You would write the same method 50 times with different values ? Very little point in using functions then.

    For naming conventions in python, I suggest you check out this link

    Don’t get discourage ! Many beginners seem to discover their first issues worth asking stack while they make a snake game. Hence I saw many beginners snake’s game. And this is one of the best I saw, you have overcomplicated some part of your code and as I mention there are plenty of points that could be greatly improved but this is still a good start ! Keep going

    Answered By: Anto
    Categories: questions Tags:
    Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
    at the top-right corner.