首页 > 解决方案 > 我的按钮操作似乎行为不端。该怎么做才能修复它或让它变得更好?

问题描述

我正在使用 Python 3.7.4 和 Pygame 1.9.6。这是我第一次使用 Python 中的面向对象;和创建按钮一样。我只是在测试这个,因为我想为我的 Space Invaders 游戏创建一个按钮。我只是不确定这是否是一种简单的方法或什么。当我想创建另一个按钮时。我只是做我对“play_again_button”所做的事情。

我想出了:

import pygame
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, screen, outline=None):
        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(screen, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('freesansbold.ttf', 60)
            text = font.render(self.text, 1, (0, 0, 0))
            screen.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 self.x < pos[0] < self.x + self.width:
            if self.y < pos[1] < self.y + self.height:
                return True

        return False


pygame.init()
screen = pygame.display.set_mode((800, 600))

running = True
play_again_button = button((20, 20, 20), (340, 340), 20, 30, 20, 'Play again')
while running:
    pygame.display.update()
    play_again_button.draw(screen)
    screen.fill((255, 255, 255))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if play_again_button.isOver(1):
                print("Clicked button")
        if event.type == pygame.MOUSEMOTION:
            if play_again_button.isOver(0):
                play_again_button.color = (255, 0, 0)
            else:
                play_again_button.color = (0, 255, 0)

无论如何,让我知道我是否应该做这样的按钮。我总是很感激反馈。

标签: pythonpygamepython-3.7

解决方案


Making a button as an object is a good idea because it makes the code easier to understand, as it wraps up all the button properties into a single data structure, with member functions to act on it.

There's a couple of bugs in your code but it's mostly OK.

When you create the button, you're passing too many parameters, and some are tuples rather than individual integers:

play_again_button = button((20, 20, 20), (340, 340), 20, 30, 20, 'Play again') # BROKEN

play_again_button = button((20, 20, 20), 340, 340, 20, 30, 'Play again')       # FIXED

Where the code does the mouse-position check, it's passing 1 or 0, and not the mouse event.pos, this is an easy fix:

if play_again_button.isOver( 1 ):

if play_again_button.isOver( event.pos ):   # FIXED

Similarly for the mouse click-check.

And Finally the screen-painting is being done in a reverse order, so that the buttons is drawn before the screen is erased, so you never see the button.

Below is code that works. I moved the offset border code inside the button class.

According to Python Style Guide PEP8, class-names Should Be Capitalised too.

Ref:

import pygame

class Button():
    def __init__(self, color, x, y, width, height, text='', outline=(0,0,0)):
        self.color   = color
        self.x       = x
        self.y       = y
        self.width   = width
        self.height  = height
        self.text    = text
        self.outline = outline

    def draw(self, screen):
        # Call this method to draw the button on the screen
        if self.outline:
            pygame.draw.rect(screen, self.outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0 )

        pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('freesansbold.ttf', 60)
            text = font.render(self.text, 1, (0, 0, 0))
            screen.blit(text, (
                self.x + int(self.width / 2 - text.get_width() / 2), self.y + int(self.height / 2 - text.get_height() / 2)))

    def setColor( self, new_colour ):
        self.color = new_color

    def isOver(self, pos):
        # Pos is the mouse position or a tuple of (x,y) coordinates
        if self.x < pos[0] < self.x + self.width:
            if self.y < pos[1] < self.y + self.height:
                return True

        return False


pygame.init()
screen = pygame.display.set_mode((800, 600))

running = True
DARK_GREY=  ( 20, 20, 20 )
play_again_button = Button( DARK_GREY, 340, 340, 20, 30, 'Play again')

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if play_again_button.isOver( event.pos ):
                print("Clicked button")
        if event.type == pygame.MOUSEMOTION:
            if play_again_button.isOver( event.pos ):
                play_again_button.setColor( (255, 0, 0) )
            else:
                play_again_button.setColor( (0, 255, 0) )

    screen.fill((255, 255, 255))
    play_again_button.draw(screen)
    pygame.display.update()

推荐阅读