【问题标题】:How can I my make buttons in pygame work properly? (HANGMAN GAME)如何让 pygame 中的 make 按钮正常工作? (刽子手游戏)
【发布时间】:2020-08-23 14:00:23
【问题描述】:

您好,我是一个 python 菜鸟,我正在尝试自己用 pygame 制作一个刽子手游戏,同时尽可能避免从 YouTube 教程中获得帮助。

我的问题是:

  1. 当我将鼠标悬停在按钮上时,按钮会改变颜色(这很好),但即使我仍然将鼠标悬停在按钮上,它也会变回来。此外,当鼠标悬停在多个按钮上时,按钮的响应性非常差。

  2. 当我单击一个按钮时,程序认为我多次单击该按钮。因为它多次执行print('clicked!') 行。

  3. 最后,当我单击一个按钮来对精灵进行 blit 时,它只会在短时间内对 sprite 进行 blit,然后它会自动取消 blit。

这是我的代码:

import pygame
pygame.init()

# DISPLAY
WIDTH, HEIGHT = 800, 500
window = pygame.display.set_mode((WIDTH, HEIGHT))
# TITLE BAR
TITLE = "Hangman"
pygame.display.set_caption(TITLE)
# HANGMAN SPRITES
man = [pygame.image.load(f"hangman{frame}.png") for frame in range(0, 7)]


class Button:

    def __init__(self, color, x, y, radius, text=""):
        self.radius = radius
        self.color = color
        self.x = x
        self.y = y
        self.width = 2
        self.text = text
        self.visible = True

    def draw(self, window, outline=None):
        if self.visible:
            if outline:
                # draws a bigger circle behind
                pygame.draw.circle(window, outline, (self.x, self.y), self.radius + 2, 0)
            pygame.draw.circle(window, self.color, (self.x, self.y), self.radius, 0)

        if self.text != "":
            if self.visible:
                font = pygame.font.SysFont("courier", 30)
                text = font.render(self.text, 1, (0, 0, 0))
                window.blit(text, (self.x - text.get_width() / 2, self.y - text.get_height() / 2))

    def hover(self, pos):
        if self.y + self.radius > pos[1] > self.y - self.radius:
            if self.x + self.radius > pos[0] > self.x - self.radius:
                return True
        return False


def main():
    run = True
    FPS = 60
    clock = pygame.time.Clock()
    large_font = pygame.font.SysFont("courier", 50)

    letters = []
    error = 0

    def redraw_window():
        window.fill((255, 255, 255))
        
        window.blit(man[0], (20, 100))
        # DRAWS LETTER BUTTONS
        for letter in letters:
            letter.draw(window, (0, 0, 0))
        pygame.display.update()

    while run:
        redraw_window()
        clock.tick(FPS)

        alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
        letter_x1, letter_y1 = 40, 375
        letter_x2, letter_y2 = 40, 435
        for i in range(13):
            letter_1 = Button((255, 255, 255), letter_x1, letter_y1, 25, alphabet[i])
            letters.append(letter_1)
            letter_x1 += 60
        for i in range(13, 26):
            letter_2 = Button((255, 255, 255), letter_x2, letter_y2, 25, alphabet[i])
            letters.append(letter_2)
            letter_x2 += 60

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            elif event.type == pygame.MOUSEMOTION:
                for letter in letters[:]:
                    if letter.hover(pygame.mouse.get_pos()):
                        letter.color = (0, 255, 0)
                    else:
                        letter.color = (255, 255, 255)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                for letter in letters:
                    if letter.hover(pygame.mouse.get_pos()):
                        print("clicked!")
                        window.blit(man[1], (20, 100))
                        pygame.display.update()
    quit()
main()

另外,我从 YouTube 上的 Tim Hangman 技术教程中获得了精灵(我只是在没有看他编写游戏代码的情况下获得了精灵,因为我想尝试自己做,以便了解更多信息)。我还从 Tech With Tim 的视频中获得了按钮类的代码。

【问题讨论】:

    标签: python button pygame


    【解决方案1】:

    首先在应用程序循环之前进行按钮的初始化,而不是在循环中连续进行

    def main():
    
        # init buttons
        alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
        letter_x1, letter_y1 = 40, 375
        letter_x2, letter_y2 = 40, 435
        for i in range(13):
            letter_1 = Button((255, 255, 255), letter_x1, letter_y1, 25, alphabet[i])
            letters.append(letter_1)
            letter_x1 += 60
        for i in range(13, 26):
            letter_2 = Button((255, 255, 255), letter_x2, letter_y2, 25, alphabet[i])
            letters.append(letter_2)
            letter_x2 += 60
    
        # application loop
        while run:
            # [...]
    

    给按钮添加属性clicked,用于存储按钮(类似于visible属性):

    class Button:
    
        def __init__(self, color, x, y, radius, text=""):
            # [...]
    
            self.visible = True
            self.clicked = False
    

    设置属性,当按钮被点击时:

    def main():
        # [...]
    
        while run:
            # [...]
            for event in pygame.event.get():
                # [...]
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    for letter in letters:
                        if letter.hover(pygame.mouse.get_pos()):
                            letter.clicked = True
    

    现在您可以根据按钮的clicked 状态绘制对象:

    def main():
        # [...]
    
        def redraw_window():
            window.fill((255, 255, 255))
            
            window.blit(man[0], (20, 100))
            # DRAWS LETTER BUTTONS
            for letter in letters:
                letter.draw(window, (0, 0, 0))
                 
                if letter.clicked:
                    # [...]
    
            pygame.display.update()
    
        # [...]
        while run:
            redraw_window()
            # [...]        
    

    或者或另外,您可以将最后一个被点击的按钮存储到一个变量 (lastLetterClicked) 并根据该变量绘制一些东西:

    def main():
        # [...]
    
        def redraw_window():
            # [...]
    
            if lastLetterClicked:
                # [...]
    
            pygame.display.update()
    
        lastLetterClicked = None
        while run:
            redraw_window()
            # [...]
    
            for event in pygame.event.get():
                # [...]
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    for letter in letters:
                        if letter.hover(pygame.mouse.get_pos()):
                            # [...]
                            lastLetterClicked = letter
    
            # [...]
    

    【讨论】:

      【解决方案2】:

      好的,让我们从第一个开始,我怀疑这里的一些更改也可能有助于解决其他问题。 nonice,您正在“while run”循环中创建“初始彩色按钮”,这意味着它会一次又一次地发生,但是您在事件 for 循环中重新着色按钮,这仅在出现新事件时才会发生。你看到问题了吗?悬停事件发生后的下一分钟,程序将只绘制一个常规按钮! 我会说这条线

        letter.color = (0, 255, 0) 
      

      被认为是 OOP 中的一个坏习惯,因为您不想在类之外更改对象属性。而是让我们构建一个“set_color”方法

       def set_color(self , color):
           self.color = color
      

      并启动按钮 letter_1 = Button((255, 255, 255), letter_x1, letter_y1, 25, alphabet[i])

      在游戏开始之前,在 while 运行循环之外

      在 while 循环中,您可以添加一个循环来绘制它们。

       for letrer in letters:
             letter.draw()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-29
        • 1970-01-01
        • 2019-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-26
        相关资源
        最近更新 更多