Search code examples
pythonpython-3.xpygamepgzero

Function is Repeating Ten Times Instead of Once - Pygame Zero


I have written a simple racing game in Pygame Zero. This comes from the MagPi "Retro Gaming with Raspberry Pi" Book. I am a beginner programmer so I might be asking an obvious question. I want to make levels. For every 100 score, level + 1. Win at 10 levels.

areas of interest might be my draw() function:

    global gameStatus, level
    screen.fill((128, 128, 128))
    if gameStatus == 0:
        car.draw()
        b = 0
        while b < len(trackLeft):
            trackLeft[b].draw()
            trackRight[b].draw()
            b += 1
        screen.draw.text("Score: " + str(score), (50, 30), color="black")
        if score % 100 == 0:
            check_levels()
        screen.draw.text("Level: " + str(level), (50, 50), color="black")
    if gameStatus == 1:
        screen.blit('rflag', (318, 268))
    if gameStatus == 2:
        screen.blit('cflag', (318, 268))

and my level_up() function:

    global level
    if level <= 10:
        level += 1
    if level == 10:
        gameStatus == 2

score is counted for every one piece of track made there is one higher score.

My problem: When I get to 100 score, level is added by 10, not by one. I don't know what seems to happen. Might it be that for every score there are a few FPS/ticks, and that as level is updated every tick, it appears that when the score hangs on 100 for about 10 ticks, the level gets update every tick?

As my program is quite short, I'll just go ahead and post all the code:

import time
from random import randint
import pygame
import pgzrun


WIDTH = 700
HEIGHT = 800


car = Actor("racecar")
car.pos = 250, 700
SPEED = 4
trackLeft = []
trackRight = []
trackCount = 0
trackPosition = 250
trackWidth = 120
trackDirection = False
gameStatus = 0
score = 0
level = 1


def draw():
    global gameStatus, level
    screen.fill((128, 128, 128))
    if gameStatus == 0:
        car.draw()
        b = 0
        while b < len(trackLeft):
            trackLeft[b].draw()
            trackRight[b].draw()
            b += 1
        screen.draw.text("Score: " + str(score), (50, 30), color="black")
        if score % 100 == 0:
            check_levels()
        screen.draw.text("Level: " + str(level), (50, 50), color="black")
    if gameStatus == 1:
        screen.blit('rflag', (318, 268))
    if gameStatus == 2:
        screen.blit('cflag', (318, 268))


def update():
    global gameStatus, trackCount
    if gameStatus == 0:
        if keyboard.left: car.x -= 2
        if keyboard.right: car.x += 2
        update_track()


def make_track():
    global trackCount, trackLeft, trackRight, trackPosition, trackWidth, score
    trackLeft.append(Actor("barrier", pos=(trackPosition - trackWidth, 0)))
    trackRight.append(Actor("barrier", pos=(trackPosition + trackWidth, 0)))
    trackCount += 1
    score += 1


def update_track():
    global trackCount, trackPosition, trackDirection, trackWidth, gameStatus
    b = 0
    while b < len(trackLeft):
        if car.colliderect(trackLeft[b]) or car.colliderect(trackRight[b]):
            gameStatus = 1
        trackLeft[b].y += SPEED
        trackRight[b].y += SPEED
        b += 1
    if trackLeft[len(trackLeft) - 1].y > 32:
        if trackDirection == False: trackPosition += 16
        if trackDirection == True: trackPosition -= 16
        if randint(0, 4) == 1: trackDirection = not trackDirection
        if trackPosition > 700 - trackWidth: trackDirection = True
        if trackPosition < trackWidth: trackDirection = False
        make_track()


def check_levels():
    global level
    if level <= 10:
        level += 1
    if level == 10:
        gameStatus = 2


make_track()


pgzrun.go()

Solution

  • You have to do the level check when the score is updated. Note, draw is executed more often then the score is updated, so if score % 100 == 0: is fulfilled multiple times and the level is incremented more than once:

    def draw():
        global gameStatus, level
        screen.fill((128, 128, 128))
        if gameStatus == 0:
            # [...]
    
            screen.draw.text("Score: " + str(score), (50, 30), color="black")
    
            # DELETE <--------------------------
            #if score % 100 == 0:
            #    check_levels()
    
            screen.draw.text("Level: " + str(level), (50, 50), color="black")
    
    def make_track():
        #[...]
        trackCount += 1
        score += 1
    
        # ADD <-----------------------------
        if score % 100 == 0:
            check_levels()
    

    Furthermore your game lags after a while, because the lists trackLeft and trackRight are continuously growing. Remove the barriers from the list which are out of the window at the bottom:

    def make_track():
        global trackCount, trackLeft, trackRight, trackPosition, trackWidth, score
        trackLeft.append(Actor("barrier", pos=(trackPosition - trackWidth, 0)))
        trackRight.append(Actor("barrier", pos=(trackPosition + trackWidth, 0)))
    
        # remove barriers which are out of screen
        if trackLeft[0].y >= HEIGHT:
            del trackLeft[0]
        if trackRight[0].y >= HEIGHT:
            del trackRight[0]
    
        trackCount += 1
        score += 1
        if score % 100 == 0:
            check_levels()