#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
: