Pygame,实现按钮的最佳方法?

时间:2019-03-28 23:19:03

标签: python pygame

我正在与一个小组一起进行pygame项目,在该项目中,我们需要能够单击按钮以选择一类对象,然后将该对象放置在网格上。

从本质上讲,这是一款塔防风格的游戏,敌人成排地产生,我需要能够放置物体来阻挡/移除它们。

我们遇到的问题是

  1. 我们无法在屏幕上绘制按钮,并且

  2. 单击后如何在屏幕上生成部队。我认为,如果单击该按钮,将以某种方式完成操作,那么它将等待网格上的鼠标输入以生成部队?

我在下面添加了按钮的代码。我们知道我们丢失了一些东西,但不清楚是什么。

button1 = button_image
button1.rect = pygame.Rect(100, 100, 50, 50)
screen.blit(button1)
if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = event.pos

        if button1.collidepoint(mouse_pos):
            print('button was pressed at {0}'.format(mouse_pos))

2 个答案:

答案 0 :(得分:0)

要完成这项工作,让我们考虑一下我们需要什么。

我们需要一些东西来表示一个按钮:一个按钮有一个文本,以及单击按钮时会调用的动作。

由于单击按钮时发生了某些事情,我们需要以某种方式表示游戏具有不同的游戏状态的事实:让我们将其描述为“游戏正在运行并且可以按下按钮”和“玩家必须为某物选择位置”。

这是它的外观。请注意这些注释(我假设pygame了解SurfaceRectSprite类等的基本知识。)

import pygame
import random

# this class is a container for 
# our game state and all the sprites
class Game:
    def __init__(self, font):
        self.font = font
        # currently we have 2 states: RUNNING and SELECT_POSITION
        self.state = 'RUNNING'

        # a sprite group for all sprites (+ UI)
        self.sprites = pygame.sprite.Group()

        # a sprite group for all game objects (- UI)
        self.actors = pygame.sprite.Group()
        self.callback = None

    def update(self, events, dt):
        for event in events:
            if event.type == pygame.MOUSEBUTTONDOWN:

                # if we're in SELECT_POSITION, a mouse click will
                # change the game state back to RUNNING
                # we pass the mouse position to the callback
                # so the action actually happens
                if self.state == 'SELECT_POSITION' and self.callback:
                    self.callback(event.pos)
                    self.state = 'RUNNING'

        # just update the sprites
        self.sprites.update(events, dt)

    def draw(self, screen):
        # usually, the background is black, but to give the player 
        # a visual clue that they have to do something, let's change
        # it to grey when we're in the SELECT_POSITION mode
        screen.fill(pygame.Color('black' if self.state == 'RUNNING' else 'grey'))

        # just draw all the sprites
        self.sprites.draw(screen)

        # just some info text for the player
        if self.state == 'SELECT_POSITION':
            screen.blit(self.font.render('Select a position', True, pygame.Color('black')), (150, 400))

    # a button can call this function when the action that should be invoked
    # needs a position that the player has to choose
    def select_position(self, callback):
        self.state = 'SELECT_POSITION'
        self.callback = callback

# just a little square guy that walks around the screen
# nothing special happens here
class WalkingRect(pygame.sprite.Sprite):
    def __init__(self, pos, color, game):
        super().__init__(game.sprites, game.actors)
        self.image = pygame.Surface((32, 32))
        self.image.fill(pygame.Color(color))
        self.rect = self.image.get_rect(center=pos)
        self.pos = pygame.Vector2(pos)
        self.direction = pygame.Vector2(random.choice([-1,0,1]), random.choice([-1,1])).normalize()

    def update(self, events, dt):
        self.pos += self.direction * dt/10
        self.rect.center = self.pos
        if random.randint(0, 100) < 10:
            self.direction = pygame.Vector2(random.choice([-1,0,1]), random.choice([-1,1])).normalize()

# the actuall Button class
# it takes an action that is invoked when the player clicks it
class Button(pygame.sprite.Sprite):
    def __init__(self, pos, color, text, game, action):
        super().__init__(game.sprites)
        self.color = color
        self.action = action
        self.game = game
        self.text = text
        self.image = pygame.Surface((150, 40))
        self.rect = self.image.get_rect(topleft=pos)
        self.fill_surf(self.color)

    def fill_surf(self, color):
        self.image.fill(pygame.Color(color))
        self.image.blit(self.game.font.render(self.text, True, pygame.Color('White')), (10, 10))

    def update(self, events, dt):

        # the player can only use the button when the game is in the RUNNING state
        if self.game.state != 'RUNNING':
            self.fill_surf('darkgrey')
            return

        self.fill_surf(self.color)
        for event in events:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if self.rect.collidepoint(event.pos):
                    # if the player clicked the button, the action is invoked
                    self.action(self.game)

def main():
    pygame.init()
    screen = pygame.display.set_mode((500, 500))
    screen_rect = screen.get_rect()
    font = pygame.font.SysFont(None, 26)
    clock = pygame.time.Clock()

    game = Game(font)

    # the action for the green button
    # when invoked, as the game for the player
    # to select a position, and spawn a green
    # guy at that position
    def green_action(game_obj):
        def create_green(pos):
            WalkingRect(pos, 'green', game_obj)
        game_obj.select_position(create_green)

    # the same but spawn a red guy instead
    def red_action(game_obj):
        def create_red(pos):
            WalkingRect(pos, 'darkred', game_obj)
        game_obj.select_position(create_red)

    Button((10, 10), 'green', 'CREATE GREEN', game, green_action)
    Button((10, 50), 'darkred', 'CREATE RED', game, red_action)

    # a button to kill all guys
    # just to show how generic our buttons are
    Button((10, 90), 'red', 'KILL', game, lambda game_obj: [x.kill() for x in game_obj.actors])

    # classic boring main loop
    # just updates and draws the game
    dt = 0
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return

        game.update(events, dt)
        game.draw(screen)

        pygame.display.flip()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

enter image description here

答案 1 :(得分:-1)

要在屏幕上获取按钮,请尝试将它们绘制为矩形(pygame.draw.rect()) 那么你可以做:
如果mouse_pos.colliderect(按钮名称可变)     scree.blit(部队[x,y])