Как я могу создать два отдельных дисплея pygame? Если я не могу, как я могу создать два экземпляра pygame?

Я хочу создать два отдельных дисплея pygame. Я знаю, что это невозможно сделать с одним экземпляром pygame. Мне было интересно, как/если бы я мог реализовать любое из следующих решений:

  1. Создайте отдельный модуль для запуска функции, использующей отдельный дисплей. Будет ли это использовать отдельный экземпляр pygame из моего основного кода и, следовательно, сможет работать?
  2. Запустите скрипт изнутри с некоторыми специальными параметрами, используя подоболочку, проанализируйте sys.argv, а затем запустите функцию во втором экземпляре. Как обеспечить кроссплатформенную совместимость?
  3. Что-то другое?

Меня не волнует, насколько неэффективной, уродливой и т.д. станет программа в результате. Я просто хочу, чтобы это работало.

Важно отметить, что основной код должен взаимодействовать с соответствующим кодом (т. е. изменять некоторые переменные, принадлежащие extraDisplayManager ниже), но я планирую использовать pickle для сохранения в файл и передачи данных таким образом. Однако я уже использую многопоточность в соответствующей части, поэтому отсутствие синхронности не имеет значения.

Мой код довольно длинный и сложный, поэтому я не буду публиковать его здесь, но суть соответствующей части такова:

def mainCode(*someargs):
    d = pygame.display.set_mode(dimensions)
    if relevantArg:
        extraDisplayManager = RelevantClass(*someotherargs)
        threading.Thread(target=extraDisplayManager.relevantFunction,
                         daemon=True).start()


...

class RelevantClass:
    def relevantFunction(self, *someotherargs):
        self.d = pygame.display.set_mode(dimensions)
        while True:
            updateDisplay(someargs) # This is part of my main code, but it
            # is standalone, so I could copy it to a new module

Я был бы признателен, если бы вы ответили на некоторые из моих вопросов или показали мне соответствующую документацию.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вам действительно (В самом деле) нужны два дисплея, вы можете использовать модуль Python многопроцессорность для создания процесса и использовать Queue для передачи данных между двумя процессами.

Вот пример, который я взломал вместе:

import pygame
import pygame.freetype
import random
import multiprocessing as mp

# a simple class that renders a button
# if you press it, it calls a callback function
class Button(pygame.sprite.Sprite):
    def __init__(self, callback, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface((200, 200))
        self.image.set_colorkey((1,2,3))
        self.image.fill((1,2,3))
        pygame.draw.circle(self.image, pygame.Color('red'), (100, 100), 50)
        self.rect = self.image.get_rect(center=(300, 240))
        self.callback = callback

    def update(self, events, dt):
        for e in events:
            if e.type == pygame.MOUSEBUTTONDOWN:
                if (pygame.Vector2(e.pos) - pygame.Vector2(self.rect.center)).length() <= 50:
                    pygame.draw.circle(self.image, pygame.Color('darkred'), (100, 100), 50)
                    self.callback()
            if e.type == pygame.MOUSEBUTTONUP:
                    pygame.draw.circle(self.image, pygame.Color('red'), (100, 100), 50)

# a simple class that display a text for 1 second anywhere
class Message(pygame.sprite.Sprite):
    def __init__(self, screen_rect, text, font, *grps):
        super().__init__(*grps)
        self.image = pygame.Surface((300, 100))
        self.image.set_colorkey((1,2,3))
        self.image.fill((1,2,3))
        self.rect = self.image.get_rect(center=(random.randint(0, screen_rect.width), 
                                                random.randint(0, screen_rect.height)))
        font.render_to(self.image, (5, 5), text)
        self.timeout = 1000
        self.rect.clamp_ip(screen_rect)

    def update(self, events, dt):
        if self.timeout > 0:
            self.timeout = max(self.timeout - dt, 0)
        else:
            self.kill()

# Since we start multiple processes, let's create a mainloop function
# that can be used by all processes. We pass a logic_init_func-function
# that can do some initialisation and returns a callback function itself.
# That callback function is called before all the events are handled.
def mainloop(logic_init_func, q):
    import pygame
    import pygame.freetype
    pygame.init()
    screen = pygame.display.set_mode((600, 480))
    screen_rect = screen.get_rect()
    clock = pygame.time.Clock()
    dt = 0
    sprites_grp = pygame.sprite.Group()

    callback = logic_init_func(screen, sprites_grp, q)

    while True:
        events = pygame.event.get()
        callback(events)

        for e in events:
            if e.type == pygame.QUIT:
                return

        sprites_grp.update(events, dt)
        screen.fill((80, 80, 80))
        sprites_grp.draw(screen)
        pygame.display.flip()
        dt = clock.tick(60)

# The main game function is returned by this function.
# We need a reference to the slave process so we can terminate it when
# we want to exit the game.
def game(slave):
    def game_func(screen, sprites_grp, q):

        # This initializes the game.
        # A bunch of words, and one of it is randomly choosen to be
        # put into the queue once the button is pressed
        words = ('Ouch!', 'Hey!', 'NOT AGAIN!', 'that hurts...', 'STOP IT')

        def trigger():
            q.put_nowait(random.choice(words))

        Button(trigger, sprites_grp)

        def callback(events):
            # in the mainloop, we check for the QUIT event
            # and kill the slave process if we want to exit
            for e in events:
                if e.type == pygame.QUIT:
                    slave.terminate()
                    slave.join()

        return callback

    return game_func

def second_display(screen, sprites_grp, q):

    # we create font before the mainloop
    font = pygame.freetype.SysFont(None, 48)

    def callback(events):
        try:
            # if there's a message in the queue, we display it
            word = q.get_nowait()
            Message(screen.get_rect(), word, font, sprites_grp)
        except:
            pass

    return callback

def main():
    # we use the spawn method to create the other process
    # so it will use the same method on each OS.
    # Otherwise, fork will be used on Linux instead of spawn
    mp.set_start_method('spawn')
    q = mp.Queue()

    slave = mp.Process(target=mainloop, args=(second_display, q))
    slave.start()

    mainloop(game(slave), q)


if __name__ == '__main__':
    main()

Конечно, это только простой пример; вам, вероятно, нужна дополнительная обработка ошибок, прекращение вложенных функций, таких как сумасшедшие, и т. д. и т. д. Кроме того, есть и другие способы сделать МПК в python.

И последнее, но не менее важное: подумайте, нужны ли вам В самом деле два дисплея pygame, потому что многопроцессорность добавляет массу сложности. Я уже ответил на некоторые вопросы о pygame на SO, и почти всегда ОП задавал вопрос XY, когда спрашивал о многопоточности/многопроцессорности с pygame.

Спасибо за подробный ответ и ссылки на документацию! Хотя это кажется довольно сложным в использовании multiprocessing, и я уверен, что есть лучшие способы сделать это (например, иметь оба «окна» рядом на одном дисплее), длина моего текущего кода гарантирует plug-and-play решение, которое вы предоставили.

101arrowz 28.05.2019 21:22

Другие вопросы по теме