为了账号安全,请及时绑定邮箱和手机立即绑定

在 Pygame 中调整大小期间更新

在 Pygame 中调整大小期间更新

慕容708150 2024-01-15 15:23:40
我正在 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 sysimport pygamepygame.init()size = 320, 240black = 0, 0, 0red = 255, 0, 0screen = 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()
查看完整描述

2 回答

?
FFIVE

TA贡献1797条经验 获得超6个赞

如果您遇到此类问题,最好使用 googleSDL来代替pygame,因为 pygame 是一个相当低级的 SDL 包装器。

所以这不是 pygame 本身的问题,而是 sdl 和窗口管理器如何交互的问题。

尽管如此,如果您确实需要在调整大小时更新窗口,如果您使用的是 Windows,则可以侦听WM_SIZEWindows 的实际事件,重绘屏幕,并通过调用 来更新“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()


查看完整回答
反对 回复 2024-01-15
?
森林海

TA贡献2011条经验 获得超2个赞

ctypes如果未指定,则假定参数类型和返回类型为 “c_int指针” 。是一个32位值。LONG_PTR 和 LRESULT 是 64 位操作系统上的 64 位值。好的做法是定义所有使用的函数和。这样做解决了问题。c_intc_int.argtypes.restype


import ctypes as ct

from ctypes import wintypes as w


import pygame


# LPARAM is typedef'ed as LONG_PTR in winuser.h, so it can be used

# for LRESULT and LONG_PTR which are missing from wintypes.

LRESULT = LONG_PTR = w.LPARAM

WNDPROC = ct.WINFUNCTYPE(LRESULT, w.HWND, w.UINT, w.WPARAM, w.LPARAM)

WM_SIZE = 0x0005

RDW_INVALIDATE = 0x0001

RDW_ERASE = 0x0004

GWL_WNDPROC = -4


# ctypes.windll.user32 is a cached, shared version of user32.dll.

# Get our own copy and meticulously define argtypes/restype according

# to MSDN documentation of the C prototypes.

user32 = ct.WinDLL('user32')

user32.GetWindowLongPtrA.argtypes = w.HWND, ct.c_int

user32.GetWindowLongPtrA.restype = LONG_PTR

user32.GetForegroundWindow.argtypes = ()

user32.GetForegroundWindow.restype = w.HWND

user32.RedrawWindow.argtypes = w.HWND, w.LPRECT, w.HRGN, w.UINT

user32.RedrawWindow.restype = w.BOOL

user32.CallWindowProcA.argtypes = WNDPROC, w.HWND, w.UINT, w.WPARAM, w.LPARAM

user32.CallWindowProcA.restype = LRESULT

user32.SetWindowLongPtrA.argtypes = w.HWND, ct.c_int, LONG_PTR

user32.SetWindowLongPtrA.restype = LONG_PTR


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()

    

    old_window_proc = user32.GetWindowLongPtrA(user32.GetForegroundWindow(), GWL_WNDPROC)


    def new_window_proc(hwnd, msg, wparam, lparam):

        if msg == WM_SIZE:

            draw_game()

            user32.RedrawWindow(hwnd, None, None, RDW_INVALIDATE | RDW_ERASE)

        # LONG_PTR is the same bit width as WNDPROC, but

        # need cast to use it here.

        return user32.CallWindowProcA(ct.cast(old_window_proc, WNDPROC), hwnd, msg, wparam, lparam)


    new_window_proc_cb = WNDPROC(new_window_proc)


    # Can't cast a WNDPROC (pointer) to a LONG_PTR directly, but can cast to void*.

    # The .value of a c_void_p instance is its integer address.

    user32.SetWindowLongPtrA(user32.GetForegroundWindow(), GWL_WNDPROC, ct.cast(new_window_proc_cb, ct.c_void_p).value)


    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()



查看完整回答
反对 回复 2024-01-15
  • 2 回答
  • 0 关注
  • 123 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信