如何使我的按钮、对象等的大小取决于 window 大小?
How do I make my buttons, objects, etc. size DEPENDENT on the window size?
我知道如何使 window 可调整大小,但如果我 运行 代码只有 window 会调整大小。按钮、对象等没有。我需要做什么才能使它们根据 window 调整大小?如果这个问题有点难以理解,你可以转到我的问题,我问的是如何调整 window 大小并阅读那里的评论。这是代码,如果你们需要的话:
import pygame
from pygame.locals import *
pygame.init()
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)
centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
class button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 60)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def isOver(self, pos):
# Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
def rescale(self):
new_size = int(WINDOW_WIDTH * self.scale_factor)
x, y = self.rect.center
self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def redrawMenuWindow():
win.fill((0, 255, 110))
greenButton.draw(win, (0, 0, 0))
redButton.draw(win, (0, 0, 0))
def redrawGameWindow():
win.fill((0, 150, 210))
pygame.draw.rect(win, (0, 250, 110),(0, 450, 800, 250))
greenButton = button((0, 255, 0), 280, 255, 250, 100, "Start")
redButton = button ((255, 0, 0), 280, 380, 250, 100, "Quit")
game_state = "menu"
run = True
while run:
if game_state == "menu":
redrawMenuWindow()
elif game_state == "game":
redrawGameWindow()
pygame.display.update()
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
elif event.type == pygame.VIDEORESIZE:
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
if event.type == pygame.MOUSEBUTTONDOWN:
if greenButton.isOver(pos):
print("clicked the button")
game_state = "game"
if redButton.isOver(pos):
print("clicked the 2button")
run = False
pygame.quit()
quit()
if event.type == pygame.MOUSEMOTION:
if greenButton.isOver(pos):
greenButton.color = (105, 105, 105)
else:
greenButton.color = (0, 255, 0)
if redButton.isOver(pos):
redButton.color = (105, 105, 105)
else:
redButton.color = (255, 0, 0)
pygame.display.update()
这样的事情有望解决问题,在您的 Button
class(class 以大写字母开头)中,添加此方法:
def resize_button(self, width, height, x, y):
self.width = width
self.height = height
self.x = x
self.y = y
然后,在 main_loop
捕捉 VIDEORESIZE
事件时:
elif event.type == pygame.VIDEORESIZE:
win = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
使用系数乘以参数得到想要的结果。玩这个。但主要思想是使按钮大小和位置相对于当前 window 大小。
还要在 main_loop
中插入 clock.tick(FPS)
并且不要忘记在循环之前添加 clock = pygame.clock.Time()
。这样您就可以控制 FPS,从而减少处理器使用量。
@kaktus_car 的回答是正确的。代码需要响应 window 大小,相应地重新缩放屏幕上的元素。
OP 代码的基本问题是 window 大小是 "hard coded",即使收到重新调整大小事件,新的 window 大小也会被遗忘。这意味着代码不知道 window 的大小,因此无法重新缩放 graphics/controls.
win = pygame.display.set_mode((800, 600), pygame.RESIZABLE) # <-- FIXED SIZE
...
elif event.type == pygame.VIDEORESIZE:
win = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE) # <-- NEW SIZE
修复起来相对简单。
第一步是存储 window 大小,并将其用于缩放屏幕上的对象。不要有一个“50x50”的盒子,有一个宽度为屏幕宽度 12% 的盒子。
(尺寸每次都可以从surface上取,但是我觉得这样很麻烦。)
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
这意味着做一些比插入坐标更难的事情。例如 window 的中心在哪里,不是“200,200”,而是:
centre_point = ( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
所以稍后当 window-size 事件发生时,这些变量可以简单地更新,并且屏幕上的对象缩放以适应:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
如果您有 sprite 对象,这些对象也可以重新缩放。将原始大小记录为比例因子。当 window 大小增加或减少时,重新应用此因子并结合精灵位图上的新大小会相应地重新缩放它。
class AlienSprite( pygame.sprite.Sprite ):
def __init__( self, bitmap, x, y ):
self.original = bitmap
self.image = bitmap
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
# Keep the existing scale factor from startup to preserve the size ratio
self.scale_factor = self.rect.width / WINDOW_WIDTH
def rescale( self ):
new_size = int( WINDOW_WIDTH * self.scale_factor ) # new size
x, y = self.rect.center # existing centre position
# Re-size the bitmap
self.image = pygame.transform.smoothscale( self.original, ( new_size, new_size ) )
self.rect = self.image.get_rect()
self.rect.center = ( x, y ) # restore to the centre point
当 pygame.VIDEORESIZE
事件发生时:
elif ( event.type == pygame.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
for s in sprite_group: # rescale all the sprites
s.rescale()
使用pygame.display.toggle_fullscreen()
命令。您可以阅读它的文档 (Link: https://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen)。
这是一个示例代码:
if event.key == K_f:
pygame.display.toggle_fullscreen()
您不必做更多。你可以制作一个按钮,你可以按下它然后使用这个命令。它真的很容易使用。希望我能帮到你,老我! :) 我今天才找到它,所以我想回答,以便您和其他人可以找到这个答案!
我知道如何使 window 可调整大小,但如果我 运行 代码只有 window 会调整大小。按钮、对象等没有。我需要做什么才能使它们根据 window 调整大小?如果这个问题有点难以理解,你可以转到我的问题,我问的是如何调整 window 大小并阅读那里的评论。这是代码,如果你们需要的话:
import pygame
from pygame.locals import *
pygame.init()
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)
centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
class button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 60)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def isOver(self, pos):
# Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
def rescale(self):
new_size = int(WINDOW_WIDTH * self.scale_factor)
x, y = self.rect.center
self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def redrawMenuWindow():
win.fill((0, 255, 110))
greenButton.draw(win, (0, 0, 0))
redButton.draw(win, (0, 0, 0))
def redrawGameWindow():
win.fill((0, 150, 210))
pygame.draw.rect(win, (0, 250, 110),(0, 450, 800, 250))
greenButton = button((0, 255, 0), 280, 255, 250, 100, "Start")
redButton = button ((255, 0, 0), 280, 380, 250, 100, "Quit")
game_state = "menu"
run = True
while run:
if game_state == "menu":
redrawMenuWindow()
elif game_state == "game":
redrawGameWindow()
pygame.display.update()
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
elif event.type == pygame.VIDEORESIZE:
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
if event.type == pygame.MOUSEBUTTONDOWN:
if greenButton.isOver(pos):
print("clicked the button")
game_state = "game"
if redButton.isOver(pos):
print("clicked the 2button")
run = False
pygame.quit()
quit()
if event.type == pygame.MOUSEMOTION:
if greenButton.isOver(pos):
greenButton.color = (105, 105, 105)
else:
greenButton.color = (0, 255, 0)
if redButton.isOver(pos):
redButton.color = (105, 105, 105)
else:
redButton.color = (255, 0, 0)
pygame.display.update()
这样的事情有望解决问题,在您的 Button
class(class 以大写字母开头)中,添加此方法:
def resize_button(self, width, height, x, y):
self.width = width
self.height = height
self.x = x
self.y = y
然后,在 main_loop
捕捉 VIDEORESIZE
事件时:
elif event.type == pygame.VIDEORESIZE:
win = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
使用系数乘以参数得到想要的结果。玩这个。但主要思想是使按钮大小和位置相对于当前 window 大小。
还要在 main_loop
中插入 clock.tick(FPS)
并且不要忘记在循环之前添加 clock = pygame.clock.Time()
。这样您就可以控制 FPS,从而减少处理器使用量。
@kaktus_car 的回答是正确的。代码需要响应 window 大小,相应地重新缩放屏幕上的元素。
OP 代码的基本问题是 window 大小是 "hard coded",即使收到重新调整大小事件,新的 window 大小也会被遗忘。这意味着代码不知道 window 的大小,因此无法重新缩放 graphics/controls.
win = pygame.display.set_mode((800, 600), pygame.RESIZABLE) # <-- FIXED SIZE
...
elif event.type == pygame.VIDEORESIZE:
win = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE) # <-- NEW SIZE
修复起来相对简单。
第一步是存储 window 大小,并将其用于缩放屏幕上的对象。不要有一个“50x50”的盒子,有一个宽度为屏幕宽度 12% 的盒子。 (尺寸每次都可以从surface上取,但是我觉得这样很麻烦。)
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
这意味着做一些比插入坐标更难的事情。例如 window 的中心在哪里,不是“200,200”,而是:
centre_point = ( WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
所以稍后当 window-size 事件发生时,这些变量可以简单地更新,并且屏幕上的对象缩放以适应:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
如果您有 sprite 对象,这些对象也可以重新缩放。将原始大小记录为比例因子。当 window 大小增加或减少时,重新应用此因子并结合精灵位图上的新大小会相应地重新缩放它。
class AlienSprite( pygame.sprite.Sprite ):
def __init__( self, bitmap, x, y ):
self.original = bitmap
self.image = bitmap
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
# Keep the existing scale factor from startup to preserve the size ratio
self.scale_factor = self.rect.width / WINDOW_WIDTH
def rescale( self ):
new_size = int( WINDOW_WIDTH * self.scale_factor ) # new size
x, y = self.rect.center # existing centre position
# Re-size the bitmap
self.image = pygame.transform.smoothscale( self.original, ( new_size, new_size ) )
self.rect = self.image.get_rect()
self.rect.center = ( x, y ) # restore to the centre point
当 pygame.VIDEORESIZE
事件发生时:
elif ( event.type == pygame.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
for s in sprite_group: # rescale all the sprites
s.rescale()
使用pygame.display.toggle_fullscreen()
命令。您可以阅读它的文档 (Link: https://www.pygame.org/docs/ref/display.html#pygame.display.toggle_fullscreen)。
这是一个示例代码:
if event.key == K_f:
pygame.display.toggle_fullscreen()
您不必做更多。你可以制作一个按钮,你可以按下它然后使用这个命令。它真的很容易使用。希望我能帮到你,老我! :) 我今天才找到它,所以我想回答,以便您和其他人可以找到这个答案!