【问题标题】:Pygame: Rect Objects Don't Render Properly in For LoopsPygame:矩形对象在 For 循环中不能正确渲染
【发布时间】:2014-09-23 16:06:36
【问题描述】:

我目前正在使用 Pygame 开发游戏,我决定将我的所有 GUI 对象组合在一个字典中,如下所示:

gui_objects = {
    # The GuiObject parameters define a rect (for positioning) and background colour.
    "healthbar" : GuiObject((10,  10, 100, 20), Colour.BLUE),
    "mini_map"  : GuiObject((10, 400,  50, 50), Colour.WHITE)
}

我像这样对 GUI 对象进行分组的原因是这样我可以轻松地修改它们:

gui_objects.get("mini_map").set_enabled(false)

现在,当我想将我的 GUI 对象渲染到屏幕上时,我只是这样做了:

for key, value in gui_objects.iteritems():
    value.render(screen)

这可行,但由于某种原因,白色的“mini_map” GuiObject 被渲染在“healthbar” GuiObject 下方。我决定将“mini_map”放在字典中“healthbar”的上方,但这并没有改变。但现在这是奇怪的部分。如果我分别渲染 GUI 对象,即分别调用它们的 render() 函数,如下所示:

gui_objects.get("healthbar").render(screen)
gui_objects.get("mini_map" ).render(screen)

然后 GuiObjects 正确重叠。我现在的问题是,当我使用 for 循环渲染它们时,为什么我的 GuiObjects 不能正确重叠?然而,它们在单独渲染时重叠得很好?

很遗憾,我无法上传图片,因为我没有足够的声誉 ¬_¬ 但是,这是源代码:

import pygame

# Just a definition of a few colours
class Colour(object):
    WHITE = (255, 255, 255)
    GREY  = (128, 128, 128)
    BLUE  = ( 64, 128, 255)

# GuiObject is just a rectangle with a colour at the moment (for testing purposes).
class GuiObject(object):
    def __init__(self, rect, colour):
        self.rect   = rect
        self.colour = colour

    def render(self, screen):
        pygame.draw.rect(screen, self.colour, self.rect)

def main():
    ############################################################################
    # Initialise
    pygame.init()
    screen = pygame.display.set_mode((800, 600))

    # if render_type = 0 then render GuiObjects using a for loop
    # if render_type = 1 then render GuiObjects separately.
    render_type = 1

    gui_objects = {
        "hpbar_bg"    : GuiObject(( 0,  0, 150, 600), (Colour.BLUE)),
        "enemy_hpbar" : GuiObject((10, 10, 200, 400), (Colour.WHITE)),
    }

    ############################################################################
    # Main loop
    while True:
        ########################################################################
        # Event Handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit(0)

        ########################################################################
        # Render
        screen.fill((0, 0, 0))

        # Here, I render the GuiObjects.
        if render_type == 0:
            # This for loop messes up overlapping.
            for key, value in gui_objects.iteritems():
                value.render(screen)
        elif render_type == 1:
            # This works fine.
            gui_objects.get("hpbar_bg").render(screen)
            gui_objects.get("enemy_hpbar").render(screen)

        pygame.display.flip()

if __name__ == "__main__":
    main()

有没有人知道为什么在使用 for 循环时重叠的 GuiObjects 不能正常工作?

我希望我已经足够清楚地解释了自己。如果不是,请询问,我会尽力澄清。

【问题讨论】:

    标签: python pygame rendering overlapping


    【解决方案1】:

    因为字典没有排序,并且它以与其他方法不同的顺序绘制对象。

    字典并不是为保存需要保持有序的对象而设计的。

    您可以:

    1. 改用 pygame 渲染 group

    这将是 pygame 推荐的存储将要绘制的对象组的方法,但是我相信您必须将 GUI 对象转换为精灵。编辑:另外,pygame 渲染组仍然没有排序,所以这不能解决您的特定问题。

    1. 改为使用元组列表 [(name,value),...](这将与您当前的方法最相似,因为这实际上是 iteritems() 字典方法返回的内容)。

    这是您使用方法 2 重写的代码:

    import pygame
    
    # Just a definition of a few colours
    class Colour(object):
        WHITE = (255, 255, 255)
        GREY  = (128, 128, 128)
        BLUE  = ( 64, 128, 255)
    
    # GuiObject is just a rectangle with a colour at the moment (for testing purposes).
    class GuiObject(object):
        def __init__(self, rect, colour):
            self.rect   = rect
            self.colour = colour
    
        def render(self, screen):
            pygame.draw.rect(screen, self.colour, self.rect)
    
    def main():
        ############################################################################
        # Initialise
        pygame.init()
        screen = pygame.display.set_mode((800, 600))
    
        # if render_type = 0 then render GuiObjects using a for loop
        # if render_type = 1 then render GuiObjects separately.
        render_type = 0
    
        gui_objects = [
            ("hpbar_bg", GuiObject(( 0,  0, 150, 600), (Colour.BLUE))),
            ("enemy_hpbar", GuiObject((10, 10, 200, 400), (Colour.WHITE))),
        ]
    
        ############################################################################
        # Main loop
        while True:
            ########################################################################
            # Event Handling
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    exit(0)
    
            ########################################################################
            # Render
            screen.fill((0, 0, 0))
    
            # Here, I render the GuiObjects.
            if render_type == 0:
                # This for loop no longer messes up overlapping.
                for key, value in gui_objects:
                    value.render(screen)
    
            pygame.display.flip()
    
    if __name__ == "__main__":
        main()
    

    因为您希望能够执行gui_objects.hpbar_bg.set_enabled(False) 之类的操作,所以我会考虑第三种选择:

    1. 重组您的代码以将 GUI 包含在一个类本身中,然后在其 draw 方法中对其组件的绘制进行排序。

    这是 3 的示例,它与您所拥有的相差不远:

    import pygame
    
    # Just a definition of a few colours
    class Colour(object):
        WHITE = (255, 255, 255)
        GREY  = (128, 128, 128)
        BLUE  = ( 64, 128, 255)
    
    # GuiObject is just a rectangle with a colour at the moment (for testing purposes).
    class GuiObject(object):
        def __init__(self, rect, colour):
            self.rect   = rect
            self.colour = colour
            self.enabled = True
    
        def render(self, screen):
            if self.enabled:
                pygame.draw.rect(screen, self.colour, self.rect)
    
    class Gui(object):
        def __init__(self):
            self.hpbar_bg = GuiObject(( 0,  0, 150, 600), (Colour.BLUE))
            self.enemy_hpbar = GuiObject((10, 10, 200, 400), (Colour.WHITE))
            self.enabled = True
    
        def render(self, screen):
            #render my gui in the order i want
            if self.enabled:
                self.hpbar_bg.render(screen)
                self.enemy_hpbar.render(screen)
    
    
    def main():
        ############################################################################
        # Initialise
        pygame.init()
        screen = pygame.display.set_mode((800, 600))
    
        gui = Gui()
    
        #uncomment to get the enabled/disabled behavior
        #gui.hpbar_bg.enabled = False
    
        #or disable the whole gui
        #gui.enabled = False
    
        ############################################################################
        # Main loop
        while True:
            ########################################################################
            # Event Handling
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    exit(0)
    
            ########################################################################
            # Render
            screen.fill((0, 0, 0))
    
            # Render GUI
            gui.render(screen)
    
            pygame.display.flip()
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

    • 感谢您抽出宝贵时间回复。我没有意识到字典没有保留项目的顺序:(我想我会试试你的第三种方法。谢谢你的帮助!
    • 您也可以使用 OrderedDict 记录添加项目的顺序,但将它们全部放在一个类中是更好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多