Pygame,实现按钮的最佳方式? [英] Pygame, best way to implement buttons?

查看:56
本文介绍了Pygame,实现按钮的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a pygame project with a group where we need to be able to click a button to select a class of objects, and then have that object be placed down on to a grid.

它本质上是一个塔防风格的游戏,其中敌人成排产生,我需要能够放置物体来阻挡/移除它们.

It is essentially a tower defense style game where enemies spawn in rows and I need to be able to place objects to block/remove them.

我们遇到的问题是

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

  1. we can't get our buttons to draw on screen and

点击后如何在屏幕上生成一个部队.我认为如果单击按钮,它将以某种方式完成,然后它将等待网格上的鼠标输入以生成部队?

how to then spawn a troop to the screen after the click. I assume it would be done in a way if the button was clicked then it will wait for a mouse input on the grid to spawn the troop?

我已经为下面的按钮添加了代码.我们知道我们遗漏了一些东西,但不清楚那是什么.

I've added the code for button below. We know we're missing something but are unclear of what that is.

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))

推荐答案

为了完成这项工作,让我们想想我们需要什么.

To make this work, let's think about what we need.

我们需要一些东西来表示一个按钮:一个按钮有一个文本,还有一个当我们点击它时调用的动作.

We need something to represent a button: a button has a text, and an action that is invoked when we click it.

由于点击按钮时会发生某些事情,我们需要以某种方式表示游戏具有不同的游戏状态:让我们将它们描述为游戏正在运行并且可以按下按钮"和'玩家必须为某事选择一个位置'.

Since something happens when a button is clicked, we need to somehow represent the fact that the game has different game states: let's describe them as 'the game is running and buttons can be pressed' and 'the player has to select a position for something'.

这就是它的样子.请注意注释(我假设对 SurfaceRectSprite 类等的工作原理有基本的 pygame 知识).

Here's how it could look like. Note the comments (I assume basic pygame knowledge of how the Surface, Rect and Sprite classes etc. work).

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()

这篇关于Pygame,实现按钮的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆