python - Pygame:矩形对象在 For 循环中无法正确渲染

标签 python pygame rendering overlapping

我目前正在使用 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 不能正常工作吗?

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

最佳答案

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

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

您可以:

  1. 使用 pygame 渲染 group相反。

这将是 pygame 推荐的存储将要绘制的对象组的方法,但是我相信您必须将 GUI 对象转换为 Sprite 。编辑:此外,pygame 渲染组仍未排序,因此这无法解决您的特定问题。

  • 使用元组列表[(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) 之类的操作,所以我会考虑第三个选项:

  • 重构代码以将 GUI 包含在类本身中,然后在其绘制方法中命令其组件的绘制。
  • 这是 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()
    

    关于python - Pygame:矩形对象在 For 循环中无法正确渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25999769/

    相关文章:

    python - 获取 numpy 数组中非零元素的数量?

    python - 无法解码图像并形成矩阵

    python - 使用 Pygame 定位移动图像/矩形

    python - Pygame fill 直到将其移出屏幕后才会更新

    javascript - 在网页上呈现 PDF

    javascript - 是否可以强制使用自定义字体在给定网页上进行文本呈现?

    python - Django:分组依据?

    python - 如何获取正在使用的 ipython 笔记本的文件路径? (相当于 __file__)

    python - pygame中的碰撞问题

    javascript - 如何在一个页面中渲染多个 angular2 组件?