Python 和 Pygame:避免创建两次显示表面



Heyo,这是我之前提出的"导入中的导入"问题的扩展,因此版主可以随意合并2。

我有 2 个文件:A.py 和 B.py

#A.py
import pygame
import B
pygame.init()
tv = pygame.display.set_mode((256, 256))
tv.blit(<some surface here>)

#B.py
import pygame
pygame.init()
tv.blit()??? <--- I need to blit to tv, but how do I do it here?

我尝试制作一个名为 Globe 的空白文件并为其分配全局值,但大多数时候我发现它只会让我的代码看起来笨拙且难以编写。也。。我也不想init两次pygame。有没有"Pythonic"的方法可以做到这一点?

这个问题实际上适用于任何结构化的python应用程序。

一个可执行的python脚本将有一个入口点。这是您为启动应用程序而调用的脚本。在此脚本中,它可以导入库模块以重用扩展功能。

应用程序需要具有单个入口点。让我们假设它将A.py.
B.py将是一个库模块,您将导入并使用其功能。它不应该期望全局tv变量进行操作。相反,它至少应该具有接受参数的函数。甚至,使用要使用的图面实例化的类。这种方法的好处是,您的B模块现在是可重用的,并且不依赖于某些可执行的主脚本,该脚本提供始终称为tv的全局图面

B.py

def blitSpecial(surf):
    surf.blit()

A.py

import B
tv = pygame.display.set_mode((256, 256))
B.blitSpecial(tv)

这是一个好习惯。如果所有模块都依赖于主脚本中的全局对象,则它们的可重用性将大大降低。

特别是针对您的pygame情况,屏幕表面的所有内容都应该在A.py中使用所有其他模块进行自定义类和实用程序函数。

你可以编写采用pygame的函数。表面对象作为参数:

class TV():
    def __init__(self):
        self.img = ... 
        ### insert code to load image here
        self.rect = self.img.get_rect()
    def draw(self, surface):
        surface.blit(self.img, self.rect.topleft)
    def erase(self, surface, background):
        surface.blit(background, self.rect)

我个人不知道与其他基于 sprite 的引擎相比,这有多快/多慢,但这是一种非常快速的方法,可以构建一个可以绘制/擦除自己的类。

要使用它,只需创建一个显示屏和一个电视对象。

screen = pygame.display.set_mode((256, 256))     
background = pygame.Surface((0,0),(256,256))
background.fill(pygame.Color(0,0,0))
screen.fill(pygame.Color(0,0,0))
myTVobj = TV()

每次您想将电视的副本绘制到您呼叫的屏幕上时

myTVobj.draw(screen)

要拭除对象,请使用

myTVobj.erase(screen, background)

然后,您可以稍后使用从TV类创建的对象做有趣的事情,例如将它们粘贴到列表中。

tv_list = []
tv_list.append(myTVobj)

您可以将一大堆电视添加到列表中,并同时绘制所有电视。

tv_list = []
tv_list.append(myTVobj)
tv_list.append(myTVobj)
tv_list.append(myTVobj)
for tv in tv_list:
    tv.draw(screen)

或者,您只需更改一行即可将它们全部删除

for tv in tv_list:
    tv.erase(screen)

最后,您可以向电视类添加另一个函数,以便移动它。如果您将 .rect 成员视为"位置标记",您所要做的就是摆弄其成员(呵呵)以更改对象的屏幕更新位置。

def move(self, move_amount=(1,0):
    self.rect.move_ip(move_amount[0], move_amount[1])

你只需要调用pygame.init()一次,所以我认为你的代码应该看起来像这样:

#A.py
import pygame
import B
def setup():
    pygame.init()
    tv = pygame.display.set_mode((256, 256))
    ...
    mysurface = ...
    tv.blit(mysurface)
    return tv

#B.py
import pygame
def mydraw(surface):
    ...
    surface.blit()
# In whatever file you like :)
if __name__ == '__main__':
    surface_A = B.setup() # Do this first
    mydraw(surface_A)

最新更新