Skip to content
Advertisement

Pygame Erases Previous Drawing

When I run the draw 3 nodes function, only the final node and link is drawn when I want all 3 nodes and links to be drawn. I did some testing and I believe it draws all of the nodes, but when it moves on to the next node it erases the previous one. I’m not 100% sure if my theory is right.

SCREEN_SIZE = (800, 800)  # (width, height)
GRID_SIZE = 8
NODE_WIDTH = 75
NODE_HEIGHT = 50
NODE_COLOUR = (0, 0, 255)
NODE_POSITION = (10, 25)
NODE_SIZE = (75, 50)
LINK_COLOUR = (255, 0, 0)
LINK_START = (NODE_POSITION[0] + 55, NODE_POSITION[1] + 25)
LINK_END = (NODE_POSITION[0] + 103,
            NODE_POSITION[1] + 25)
LIST_OF_EVENTS = []


################################################################################
# Pygame helper functions (don't change these!)
################################################################################
def initialize_screen(screen_size: tuple[int, int], allowed: list) -> pygame.Surface:
    """Initialize pygame and the display window.

    allowed is a list of pygame event types that should be listened for while pygame is running.
    """
    pygame.display.init()
    pygame.font.init()
    screen = pygame.display.set_mode(screen_size)
    screen.fill(THECOLORS['white'])
    pygame.display.flip()

    pygame.event.clear()
    pygame.event.set_blocked(None)
    pygame.event.set_allowed([pygame.QUIT] + allowed)

    return screen


def draw_text(screen: pygame.Surface, text: str, pos: tuple[int, int]) -> None:
    """Draw the given text to the pygame screen at the given position.

    pos represents the *upper-left corner* of the text.
    """
    font = pygame.font.SysFont('inconsolata', 22)
    text_surface = font.render(text, True, THECOLORS['black'])
    width, height = text_surface.get_size()
    screen.blit(text_surface,
                pygame.Rect(pos, (pos[0] + width, pos[1] + height)))


def draw_grid(screen: pygame.Surface) -> None:
    """Draws a square grid on the given surface.

    The drawn grid has GRID_SIZE columns and rows.
    You can use this to help you check whether you are drawing nodes and edges in the right spots.
    """
    color = THECOLORS['grey']
    width, height = screen.get_size()

    for col in range(1, GRID_SIZE):
        x = col * (width // GRID_SIZE)
        pygame.draw.line(screen, color, (x, 0), (x, height))

    for row in range(1, GRID_SIZE):
        y = row * (height // GRID_SIZE)
        pygame.draw.line(screen, color, (0, y), (width, y))


################################################################################
# 1. Drawing nodes and links
################################################################################
def draw_node(screen: pygame.Surface, node: _Node, pos: Tuple[int, int]) -> None:
    """Draw a node on the screen at the given position.

    pos represents the coordinates of the *top-left* corner of the node.

    Your drawing of the the node should include:
        - A rectangle split vertically into two halves.
        - The item stored in the node, displayed in the left half.
          You may assume the string representation of item is at most 3 characters
          long. You'll need to use the draw_text function we've provided above.

    NOTE: Do not draw the arrow representing the link to the next node in this function.
    You'll implement that part of the visualization separately in the draw_link function.

    We strongly recommend initializing new constants at the top of this file to represent
    node width, height, and colour.

    >>> linky = LinkedList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    >>> draw_node(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS), linky.first, NODE_POSITION)
    """
    draw_grid(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS))

    pygame.draw.rect(screen, NODE_COLOUR, pygame.Rect(pos, NODE_SIZE), 1)
    pygame.draw.line(screen, NODE_COLOUR, (pos[0] + 37, pos[1] + 50), (pos[0] + 37, pos[1]), 1)
    draw_text(screen, str(node.item), (pos[0] + 5, pos[1] + 15))


def draw_link(screen: pygame.Surface, start: Tuple[int, int], end: Tuple[int, int]) -> None:
    """Draw a line representing a link from `start` to `end`.

    To indicate which end is the "start" of the line, draw a small circle at the starting point
    (like the diagrams we've seen in class).

    The rest of your link can be a simple line; you may, but are not required, to draw an
    arrowhead at the end of the line.

    >>> draw_link(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS), LINK_START, LINK_END)
    """
    pygame.draw.circle(screen, NODE_COLOUR, start, 5)
    pygame.draw.line(screen, LINK_COLOUR, start, end)


def draw_three_nodes(screen_size: Tuple[int, int]) -> None:
    """Draw three nodes on a pygame screen of the given size.

    You may choose the coordinates for the nodes, as long as they do not overlap with each other
    and are separated by at least 10 pixels. Each link must start in the CENTRE of the start node's
    right half, and must end on the border of the end node (not inside the end node).
    This matches the style of node from lecture.

    The third node should link to "None", which you should visualize by calling draw_text.
    >>> draw_three_nodes(SCREEN_SIZE)
    """
    screen = initialize_screen(screen_size, [])

    increment = 0

    node1 = _Node(1)
    node2 = _Node(2)
    node3 = _Node(3)
    node1.next = node2
    node2.next = node3

    curr = node1

    while curr is not None:
        draw_node(screen, node1, (NODE_POSITION[0] + increment, NODE_POSITION[1]))
        draw_link(screen, (LINK_START[0] + increment, LINK_START[1]),
                  (LINK_END[0] + increment, LINK_END[1]))
        increment += 100
        curr = curr.next

    # Don't change the code below (it simply waits until you close the Pygame window)
    pygame.display.flip()
    pygame.event.wait()
    pygame.display.quit()

Advertisement

Answer

Inside the draw_node function, you’re reinitializing the screen for drawing each node.

draw_grid(initialize_screen(SCREEN_SIZE, LIST_OF_EVENTS))

I think this is the reason why your screen isn’t persistent. Instead of initializing the screen inside the draw_node function for each individual node, initiliaze it only once in draw_three_nodes.

6 People found this is helpful
Advertisement