Python и Pygame: избегать создания поверхности дисплея дважды

Эй, это немного расширение вопроса "Импорт в импорте", заданного мной ранее, поэтому модераторы могут свободно объединять 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" способ сделать это?

3 ответа

Решение

Этот вопрос может действительно относиться к любому структурированному приложению 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.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)

Вы можете написать функции, которые принимают объекты pygame.Surface в качестве параметров:

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)

Лично я не знаю, насколько это быстро / медленно по сравнению с другими движками на основе спрайтов, но это очень быстрый способ создать класс, который может рисовать / стирать сам себя.

Чтобы использовать его, просто создайте экран дисплея и телевизионный объект.

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])
Другие вопросы по тегам