Обновление во время изменения размера в Pygame

#python #pygame

#python #графика #pygame #изменение размера

Вопрос:

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

 pygame.display.set_mode((740, 440), pygame.RESIZABLE)
 

А также следующее в моем обработчике событий:

 elif event.type == pygame.VIDEORESIZE:
     game.screen = pygame.display.set_mode((event.w, event.h),
                                            pygame.RESIZABLE)
     # Code to re-size other important surfaces
 

Проблема, с которой я сталкиваюсь, заключается в том, что это похоже на pygame.Событие VIDEORESIZE запускается только после того, как пользователь завершит изменение размера окна, т.Е. отпустит границу. screen.get_size() обновляется аналогичным образом. Поскольку графика в моей игре очень простая, я бы предпочел, чтобы они изменялись по мере перетаскивания окна пользователем. Это тривиально на многих других языках, но я не могу найти никаких ссылок на это в pygame — хотя я не могу представить себе такую базовую функцию, которая была бы невозможна.

Как я могу обновить свою игру при изменении размера экрана в pygame?

РЕДАКТИРОВАТЬ: вот минимальный рабочий пример. Следующий код, запущенный в Windows 10, pygame 1.9.4, нарисует обновленный прямоугольник только после того, как пользователь закончит перетаскивать окно.

 import sys
import pygame

pygame.init()

size = 320, 240
black = 0, 0, 0
red = 255, 0, 0

screen = pygame.display.set_mode(size, pygame.RESIZABLE)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.VIDEORESIZE:
            pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)

    screen.fill(black)
    pygame.draw.rect(screen, red, (10,10,screen.get_width(),screen.get_height()))
    pygame.display.flip()
 

Комментарии:

1. У меня нет решения, но я сталкивался с подобной проблемой раньше и в конечном итоге переключал технологии (частично) из-за этого. Если есть способ сделать это, это, конечно, непросто.

2. Я не получаю такого поведения при запуске PyGame 1.9.4 под Linux Python 3.7.5. Я могу изменять размер окна, как аккордеон, и мое окно просто обновляется нормально. Пожалуйста, укажите свои данные об операционной системе и больше кода в вопросе. Возможно, проблема в коде, а не в изменении размера PyGame.

3. @Kingsley Вместо того, чтобы пытаться сжать мой код, я бы направил вас к этому видео: youtube.com/watch?v=edJZOQwrMKwamp;t=208s Вы можете видеть, как в очень простом примере не удается правильно изменить размер до тех пор, пока не выйдет Windows 10 (на которой я работаю).

4. @Kingsley Я включил минимальный рабочий пример с прямоугольником вместо моей сетки. Я также работаю с pygame 1.9.4 и Python 3.7.5.

5. Спасибо за пример. Я вижу такое же поведение в Win10, Python 3.7.5 и Pygame 2.0.0.dev22 (который использует SDL 2.0.12). Некоторые поисковые запросы указывают на проблему SDL. T

Ответ №1:

Если вы столкнетесь с такой проблемой, всегда стоит использовать Google SDL вместо pygame , поскольку pygame — довольно низкоуровневая оболочка SDL.

Так что это не проблема самой pygame, а скорее то, как взаимодействуют sdl и ваш оконный менеджер, например, см. Этот Отчет об ошибке SDL .

Тем не менее, если вам действительно нужно обновить окно во время изменения размера, если вы используете Windows, вы можете прослушать фактическое WM_SIZE событие Windows, перерисовать экран и обновить окно «Windows», вызвав RedrawWindow .

Вот простой пример:

 import pygame
import win32gui
import win32con

def wndProc(oldWndProc, draw_callback, hWnd, message, wParam, lParam):
    if message == win32con.WM_SIZE:
        draw_callback()
        win32gui.RedrawWindow(hWnd, None, None, win32con.RDW_INVALIDATE | win32con.RDW_ERASE)
    return win32gui.CallWindowProc(oldWndProc, hWnd, message, wParam, lParam)

def main():
    pygame.init()

    screen = pygame.display.set_mode((320, 240), pygame.RESIZABLE | pygame.DOUBLEBUF)

    def draw_game():
        screen.fill(pygame.Color('black'))
        pygame.draw.rect(screen, pygame.Color('red'), pygame.Rect(0,0,screen.get_width(),screen.get_height()).inflate(-10, -10))
        pygame.display.flip()
    
    oldWndProc = win32gui.SetWindowLong(win32gui.GetForegroundWindow(), win32con.GWL_WNDPROC, lambda *args: wndProc(oldWndProc, draw_game, *args))

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            elif event.type == pygame.VIDEORESIZE:
                pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE| pygame.DOUBLEBUF)
        draw_game()
        
if __name__ == '__main__':
    main()
 

Поведение по умолчанию:

введите описание изображения здесь

С RedrawWindow :

введите описание изображения здесь