[Python] Creating a class instance causes pygame to draw a black screen for 1 frame

Discussão em 'Python' iniciado por Stack, Junho 27, 2025.

  1. Stack

    Stack Membro Participativo

    I have different screens/menus set as instances of the Scene class. Whenever I want to switch screens, my gameloop checks for a button click, and if successful, it calls a function that defines the components of a screen and combines it into a Scene instance. However, when I switch screens a black screen is rendered for 1 frame. Through a series of wait commands, I've found that the line

    combatscreen = Scene("combatscreen", settings["resolution"]["x"], settings["resolution"]["y"], [50, 50, 50], [atkbtn, backbtn])


    is responsible, though I'm not sure how, as no display update is called.

    This is the necessary code to run the window and trigger the bug:

    import pygame
    import sys
    import types
    import json

    pygame.init()

    with open("settings.json") as file:
    settings = json.load(file)

    class Scene:
    all_scenes = []

    def __init__(self, name, sizex, sizey, bgcolor, buttons=[], textboxes=[]):
    self.name = name
    self.sizex = sizex
    self.sizey = sizey
    self.bgcolor = bgcolor
    self.buttons = buttons
    self.textboxes = textboxes
    self.active = False
    Scene.all_scenes.append(self)
    self.surface = pygame.display.set_mode(size=[sizex, sizey])

    class Button:
    def __init__(self, dest, destargs, posx, posy, width, height, text, color=[200,200,200], textcolor=[0,0,0], textsize=40):
    self.dest = dest
    self.destargs = destargs
    self.posx = posx
    self.posy = posy
    self.width = width
    self.height = height
    self.text = text
    self.color = color
    self.textcolor = textcolor
    self.textsize = textsize

    def btnclick(self, prev_scene):
    mpos = pygame.mouse.get_pos()
    clicks = pygame.mouse.get_just_released()
    btnbounds = pygame.draw.rect(self.surface, self.color, (self.posx, self.posy, self.width, self.height))
    # Checks if LMB was clicked within the bounds of the button
    if btnbounds.collidepoint(mpos):
    if clicks[0]:
    if isinstance(self.dest, types.FunctionType):
    # Deactivates current scene and runs the function to define and activate the destination scene
    prev_scene.active = False
    self.dest()
    else:
    pass

    def btnrender(self):
    mpos = pygame.mouse.get_pos()
    btnrect = pygame.draw.rect(self.surface, self.color, (self.posx, self.posy, self.width, self.height))
    if btnrect.collidepoint(mpos):
    # Makes the button lighter when hovered
    self.color[0] += 20
    self.color[1] += 20
    self.color[2] += 20
    pygame.draw.rect(self.surface, self.color, (self.posx, self.posy, self.width, self.height))
    # Resets button color
    self.color[0] -= 20
    self.color[1] -= 20
    self.color[2] -= 20
    btnlabel = pygame.font.Font(filename="Assets\\Fonts\\Adhynatha.otf", size=self.textsize).render(self.text, antialias=True, color=self.textcolor)
    labelrect = btnlabel.get_rect(center=(self.posx+(self.width/2), self.posy+(self.height/2)))
    self.surface.blit(btnlabel, labelrect)

    def gameloop():
    scene = None
    while True:
    # Find which scene is active
    for i in Scene.all_scenes:
    if i.active:
    scene = i
    # Apply the active scene's surface to the buttons
    for i in scene.buttons:
    i.surface = scene.surface
    # Set the background color and render buttons
    scene.surface.fill(scene.bgcolor)
    for i in scene.buttons:
    i.btnrender()
    # Update the screen and restart the loop
    pygame.display.flip()
    # Pump the event queue
    for event in pygame.event.get():
    # Game close check
    if event.type == pygame.QUIT:
    sys.exit()
    pygame.quit()
    # Check if a button has been clicked this frame
    for i in scene.buttons:
    i.btnclick(scene)
    pygame.time.Clock().tick(60)

    def startscreen():
    startbtn = Button(combatscreen, None, 100, 100, 300, 100, "Start", [30, 30, 30], "white")
    cnfgbtn = Button("settingsmenu", None, settings["resolution"]["x"]-400, 100, 300, 100, "Settings", [30, 30, 30], "white")
    # PROBLEM LINE
    startscreen = Scene("startscreen", settings["resolution"]["x"], settings["resolution"]["y"], [100, 100, 100], [startbtn, cnfgbtn])
    startscreen.active = True

    def combatscreen():
    atkbtn = Button("attack_select", None, 100, 500, 300, 100, "Combat", [100, 100, 100], textcolor="red")
    backbtn = Button(startscreen, None, settings["resolution"]["x"]-100, 0, 100, 50, "Back", textsize=20, textcolor="Black")
    # PROBLEM LINE
    combatscreen = Scene("combatscreen", settings["resolution"]["x"], settings["resolution"]["y"], [50, 50, 50], [atkbtn, backbtn])
    combatscreen.active = True

    startscreen()
    gameloop()


    I've tried reordering various events in the gameloop, but because the issue supposedly comes from an instance creation in a separate function, it hasn't changed anything.

    Continue reading...

Compartilhe esta Página