调整游戏屏幕大小时,按钮点击框出错

2024-04-24 13:16:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我的代码基本如下: 我有一个菜单,上面有按钮,它们是在主屏幕的副本上绘制的,主屏幕允许它平滑缩放,正在绘制的按钮是在类中

鼠标选择或触摸按钮后,它将显示“悬停”动画,可以单击以执行命令。问题是,一旦屏幕调整大小;无论大小,按钮的碰撞点都是混乱的,这意味着它与实际的按钮不一致,这意味着它不能被直接点击

未调整大小:https://cdn.discordapp.com/attachments/497262963888095234/898846334776377344/PXL_20211016_081328820.jpg

调整大小:https://cdn.discordapp.com/attachments/497262963888095234/898846334193385482/PXL_20211016_081343846.jpg

主代码:

import pygame
import sys
from pygame.locals import *
from buttonClass import Button

running = True

pygame.init()
mainClock = pygame.time.Clock()
win = pygame.display.set_mode((1300, 800), HWSURFACE|DOUBLEBUF|RESIZABLE) # Sets the height and width of window, anything on the screen goes on 'win'
fakeMenuScreen = win.copy()


# Load background images
bar = pygame.image.load("menuimages/bar.png").convert_alpha()

sprites = pygame.sprite.Group()
singleplayerButton = sprites.add(Button(pygame.Color((0, 0, 0, 0)), 
                   pygame.Color((53, 74, 110, 50)), pygame.Rect(85, 250, 375, 50), lambda x : print('HELLO'), "Singleplayer"))

multiplayerButton = sprites.add(Button(pygame.Color((0, 0, 0, 0)), pygame.Color((53, 74, 110, 50)), 
                   pygame.Rect(85, 320, 375, 50), lambda b: print(f"Button '{b.text}' was clicked"), 'Multiplayer',))



def main_menu():
    global win
    while running == True: 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
          
            if event.type == VIDEORESIZE:
                win = pygame.display.set_mode(event.size, RESIZABLE)

        
        win.blit(pygame.transform.smoothscale(fakeMenuScreen, win.get_rect().size), (0, 0)) # Smooths and scales out the screen

        fakeMenuScreen.blit(bar, (85, 0))  

        sprites.update(pygame.event.get()) # Buttons

        sprites.draw(fakeMenuScreen) # draw all sprites/Buttons

        pygame.display.update()

if __name__ == "__main__":
    main_menu()

按钮类py:

import pygame

pygame.init()
font = pygame.font.SysFont('Microsoft New Tai Lue', 23)
font2 = pygame.font.SysFont('Tw Cen MT Condensed Extra Bold', 18)

class Button(pygame.sprite.Sprite):
    def __init__(self, color, color_hover, rect, callback, text='', outline=None):
        super().__init__()
        self.text = text
        # a temporary Rect to store the size of the button
        tmp_rect = pygame.Rect(0, 0, *rect.size)

        # create two Surfaces here, one the normal state, and one for the hovering state
        self.org = self._create_image(color, outline, text, tmp_rect)
        self.hov = self._create_image(color_hover, outline, text, tmp_rect)

        # in Sprites, the image attribute holds the Surface to be displayed...
        self.image = self.org
        # ...and the rect holds the Rect that defines it position
        self.rect = rect
        self.callback = callback



    def _create_image(self, color, outline, text, rect):
        # function to create the actual surface
        img = pygame.Surface(rect.size, pygame.SRCALPHA)
        if outline:
            # 'inflate' is used to 'shrink' the rect
            img.fill(outline)
            img.fill(color, rect.inflate(-4, -4))
        else:
            img.fill(color)

        # render the text once here instead of every frame
        if text != '':
            text_surf = font.render(text, 1, pygame.Color('white'))
            text_rect = text_surf.get_rect(center=rect.center)
            img.blit(text_surf, text_rect)
        return img

    def update(self, events):
        # here we handle all the logic of the Button
        pos = pygame.mouse.get_pos()
        print(pos)
        hit = self.rect.collidepoint(pos)

        self.image = self.hov if hit else self.org
        for event in events:
            # if this Button is clicked, it runs the callback function
            if event.type == pygame.MOUSEBUTTONDOWN and hit:
                    self.callback(self)

非常感谢您的帮助


Tags: thetextrectimageselfeventimgif
2条回答

问题是,您没有修改调整大小窗口的鼠标数据。
幸运的是,我以前也有同样的问题,并写了以下课程:

class Window:
    def __init__(self, surf, width, height):
        self.screen = pygame.display.set_mode((width, height), RESIZABLE)  # add your flags here
        self.surf = surf
        # self.orig_w, self.orig_h = surf.get_size()
        # self.x_off = 0
        # self.y_off = 0
        self.width = width
        self.height = height
        # self.rate = 1
        # self.set_sizes(width, height)

    def set_sizes(self, width, height):
        # self.rate = min(width / self.orig_w, height / self.orig_h)
        # self.width = int(self.orig_w * self.rate)
        # self.x_off = int((width - self.width) / 2)
        # self.height = int(self.orig_h * self.rate)
        # self.y_off = int((height - self.height) / 2)
        ##### code below inserted
        self.width = width
        self.height = height

    def get_mouse_pos(self):
        mouse_x, mouse_y = pygame.mouse.get_pos()
        # return int((mouse_x - self.x_off) / self.rate), int((mouse_y - self.y_off) / self.rate)
        ###### code below inserted
        return mouse_x / self.width * self.orig_width, mouse_y / self.height * self.orig_height

    def update(self):
        self.screen.fill((50, 50, 50))
        # self.screen.blit(pygame.transform.smoothscale(self.surf, (self.width, self.height)), (self.x_off, self.y_off))
        # code below inserted
        ###### self.screen.blit(pygame.transform.smoothscale(self.surf, (self.width, self.height)), (0, 0))
        ###### code below original
        pygame.display.flip()

用法:

  • 使用fakeMenuScreen = pygame.Surface((1300, 800))win = Window(fakeMenuScreen, 1300, 800)
  • VIDEORESIZE事件中,您应该调用win.set_sizes(event.w, event.h)
  • 获取鼠标位置时,应使用wind.get_mouse_pos()
  • 要更新窗口,需要调用win.update()

其他功能:
调整大小时,显示的窗口将保持其宽高比,并在侧面显示灰色条

所以基本上我用了一个比例因子来缩放屏幕上的坐标:

scaleX = screenWidth / infoObject.current_w
finalPosX = int(round(pygame.mouse.get_pos()[0] * scaleX))

scaleY = screenHeight / infoObject.current_h
finalPosY = int(round(pygame.mouse.get_pos()[1] * scaleY))

sprites.update(events, (finalPosX, finalPosY))

然后,坐标被传递给button类中的update函数,该函数更新Hitbox

相关问题 更多 >