在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
red = 255,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,pygame.RESIZABLE)

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

解决方法

如果遇到这种问题,因为pygame是一个非常底层的SDL包装器,使用SDL而不是pygame来搜索它总是值得的。

所以这不是pygame本身的问题,而是sdl和您的窗口管理器如何交互,例如参见this SDL bug report

尽管如此,如果您确实需要在调整大小时更新窗口,如果您使用的是Windows,则可以收听Windows的实际WM_SIZE事件,重绘屏幕并更新“ 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,win32con.RDW_INVALIDATE | win32con.RDW_ERASE)
    return win32gui.CallWindowProc(oldWndProc,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,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()

默认行为:

enter image description here

使用RedrawWindow

enter image description here