Search code examples
pythonpygame

Display flickering in pygame (how to make my code more efficient)


Although Python is really slow I want to try to make a 3D game engine in pygame. And I already have a problem: display flickers when I add more than just one object. You can view my code here (to view the result you need to run the test.py file, tdge.py functions as a library). How can I make it more efficient? Here is the main part of this code:

# this function handles the drawing objects on the display
def draw(game, object):

    # updating the background if game.update is True
    if game.update:
        if game.image_path: game.win.blit(game.image, (0, 0))
        else: game.win.fill(game.color)

    # checking the type of the given object
    if type(object) == Cube:

        # getting the height of the game window
        height = game.win.get_height()
        # getting the width of the game window
        width = game.win.get_width()
        # getting the X distance between the object and the user
        distanceX = game.position[0] - object.position[0]
        # getting the Z distance between the object and the user
        distanceZ = game.position[2] - object.position[2]
        # setting the size of the object that user will actually see
        display_size = []
        for size in object.size:
            if game.position[2] < object.position[2]:
                display_size.append(size / distanceZ * 1000)
            else: display_size.append(0)
        # creating a position list, storing the position of an object on a 3D coordinate plane
        position = [width / 2 - distanceX - display_size[0] / 2, height / 2 - object.position[1] - display_size[1] / 2, object.position[2]]

        # if player is not "inside" of the object
        if game.position[0] > position[0] + object.size[0] / 2 or \
            game.position[0] < position[0] - object.size[0] / 2 and \
                game.position[1] > position[1] + object.size[1] / 2 or \
                    game.position[1] < position[1] - object.size[1] / 2 and \
                        game.position[2] > position[2] + object.size[2] / 2 or \
                            game.position[2] < position[2] - object.size[2] / 2:

            # if the rotation of the player is [0, 0, 0]
            if game.rotation == [0, 0, 0]:
                # if the rotation of the object is [0, 0, 0]
                if object.rotation == [0, 0, 0]:
                    # drawing a 2D rectangle
                    pygame.draw.rect(game.win, object.color, ((position[0], position[1]), (display_size[0], display_size[1])))
                # if rotation of the object is not [0, 0, 0]
                else:
                    # if the object is rotated on Y axis
                    if object.rotation[1] != 0:
                        # getting the sizes on X axis
                        y_rotation = object.rotation[1]
                        percent = 100 / (90 / y_rotation)
                        x_size = display_size[0]
                        x0 = x_size / 100 * percent
                        x1 = x_size - x0
                        number = 255 - (255 / 100 * percent)

                        # setting the RGB values
                        color0 = object.color[0] - number if object.color[0] >= number else 0
                        color1 = object.color[1] - number if object.color[1] >= number else 0
                        color2 = object.color[2] - number if object.color[2] >= number else 0

                        # drawing two 2D rectangles based on the data above
                        pygame.draw.rect(game.win, (color0, color1, color2), ((position[0], position[1]), (x0, display_size[1])))
                        pygame.draw.rect(game.win, object.color, ((position[0]+x0, position[1]), (x1, display_size[1])))
                # else:
                    # TODO
                    # write code for displaying object when it is to the right or to the left of the player
                    # pass

        # adding the object if it is not in game.objects
        if object not in game.objects:
            game.objects.append(object)
    else:
        error = "You should provide the object of supported type by this library."
        raise TypeError(error)

    # update the screen so that user will see the difference
    pygame.display.update()

Solution

  • The problem is most likely caused by multiple calls to pygame.display.update(). An update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.

    Remove all calls to pygame.display.update() from your code, but call it once at the end of the application loop:

    def start_game(game, code=None):
        # [...]
    
        while running:
            # [...]
    
            pygame.display.update()
            clock.tick(120)