Pygame小工具:模拟键盘 - 虚拟键盘(Keyboard)

宅在家里,沉迷于pygame编程,这篇文章给大家分享一下基于pygame实现一些简单的小功能,这些功能可以很好的嵌入在游戏中增加游戏的交互性。

这篇文章主要讲述用pygame实现虚拟键盘的方式。

目录

1. 效果 & 功能

2. 代码

2.1. 按钮

2.2. 处理输入

2.3. 显示 

2.3. 运行

3. 结语


1. 效果 & 功能

  • 主要实现功能有:
    • 输入0-9a-z间的字符
    • ‘del’进行删除
    • ‘end’结束输入

demo演示

2. 代码

首先引用基础库和声明一些常量方便之后更改。

SCREEN_SIZE = 1000, 500 # 屏幕大小

# 一些常用颜色
WHITE = 255, 255, 255
GRAY = 190, 190, 190
BLACK = 0, 0, 0
LINEN = 250, 240, 230
DARKSLATEGRAY = 47, 79, 79

PAD = 10 # 各物块,按钮之间的 padding
FPS = 60 # pygame显示的fps

DISPLAY_FONT = (None, 40) # 显示打印文字的字体
DISPLAY_BG_COLOR = LINEN  # 显示打印文字区域的背景色
DISPLAY_TEXT_COLOR = DARKSLATEGRAY # 打印文字的颜色

KEYBOARD_FONT = (None, 30) # 按钮字体
KEYBOARD_BUTTON_SIZE = 40, 40 # 按钮大小
KEYBOARD_BG_COLOR = WHITE # 按钮背景色
KEYBOARD_BG_COLOR_CLICKED = GRAY # 按钮被选中时的背景色
KEYBOARD_TEXT_COLOR = BLACK # 按钮文字颜色

2.1. 按钮

首先时虚拟按钮的实现,我们在这里将每一个按钮都当作一个pygame.sprite.Sprite类,具体代码如下:

class KeyboardButton(pygame.sprite.Sprite):
    def __init__(self, **kwargs):
        # 创建按钮时需要有多个参数
        # size :按钮的大小
        # value :按钮的显示值
        # id : 按钮的id
        pygame.sprite.Sprite.__init__(self)
        self.size = kwargs.get('size')
        self.value = kwargs.get('value')
        if kwargs.get('id'):
            self.id = kwargs.get('id')
        else :
            # 若没有id,则我们默认self.value为按钮的self.id
            self.id = self.value
        self.clicked = False # 按钮是否被选中
        self.render_image() # 渲染按钮显示图像

    def render_image(self):
        # 主要渲染两个图像:
        # self.image_org为原始图像
        # self.image_clicked为选中时的图像
        font = pygame.font.Font(*KEYBOARD_FONT)
        w, h = font.size(self.value)
        # 初始化Surface
        self.rect = Rect(0, 0, *self.size)
        self.image_org = pygame.Surface(self.size).convert()
        self.image_org.fill(KEYBOARD_BG_COLOR)
        # 居中渲染self.value
        self.image_org.blit(font.render(self.value, True, KEYBOARD_TEXT_COLOR),
                            ((self.size[0] - w) // 2, (self.size[1] - h) // 2))
        self.image_clicked = self.image_org.copy()
        self.image_clicked.fill(KEYBOARD_BG_COLOR_CLICKED)
        self.image_clicked.blit(font.render(self.value, True, KEYBOARD_TEXT_COLOR),
                                ((self.size[0] - w) // 2, (self.size[1] - h) // 2))
        self.image = self.image_org

    def update(self):
        # 根据该按钮是否被选中决定显示图像
        if self.clicked:
            self.image = self.image_clicked
        else:
            self.image = self.image_org

我们将把按钮都放入一个SpriteGroup中进行update, update时我们需要三个参数 (args = mouse_x, mouse_y, mouse_clicked) : 

mouse_x, mouse_y, mouse_clicked (鼠标的位置,以及鼠标点击与否)

mouse_clicked = True (鼠标按下) | False (鼠标按上) | None (其它)

class KeyboardButtonGroup(pygame.sprite.Group):
    def __init__(self):
        pygame.sprite.Group.__init__(self)

    def update(self, *args):
        mouse_x, mouse_y, mouse_clicked = args
        for s in self.sprites():
            if s.rect.collidepoint(mouse_x, mouse_y):
                # 鼠标触碰按钮
                # 若鼠标按下
                if mouse_clicked == True:
                    s.clicked = True
                # 若鼠标按上
                elif mouse_clicked == False:
                    if s.clicked:
                        # 若鼠标按上且之前按下时点击的该按钮
                        s.clicked = False
                        add_input(s.id)
            else:
                if mouse_clicked == False:
                    s.clicked = False
            s.update() # 更新按钮的显示

2.2. 处理输入

在这里,我们定义一个类用于存放输入的字符并进行处理,注意在 KeyboardButtonGroup 中,我们通过 add_input(s.id) 用于处理得到的输入,这一部分我们讲述如何实现该功能。

class Keyboard():
    keyboard_input = [] # 存放input
    output = False # 是否最终输出
def empty_keyboard():
    # 初始化Keyboard中的变量
    Keyboard.keyboard_input = []
    Keyboard.output = False


def add_input(value):
    # 新的输入
    if value == 'del': # 删除
        if Keyboard.keyboard_input:
            Keyboard.keyboard_input.pop()
    elif value == 'end': # 输入完毕
        Keyboard.output = True
    else: # 普通输入
        Keyboard.keyboard_input.append(value)


def get_keyboard_input():
    return Keyboard.keyboard_input


def end_of_input():
    return Keyboard.output

2.3. 显示 

显示有两个区域,一个是显示输入区域,一个是按钮区域

def keyboard(screen):
    empty_keyboard()
    mouse_x, mouse_y, mouse_clicked = 0, 0, None

    keyboard_button_grp = KeyboardButtonGroup()  # 初始化按钮
    for value in [str(i) for i in range(10)] + [chr(i) for i in range(ord('a'), ord('a') + 26)] + ['del', 'end']:
        keyboard_button_grp.add(KeyboardButton(size=KEYBOARD_BUTTON_SIZE, value=value))

    KEYBOARD_BUTTON_PER_ROW = 10  # 每行的按钮数量
    keyboard_rows = (len(keyboard_button_grp) - 1) // KEYBOARD_BUTTON_PER_ROW + 1  # 按钮的总行数
    KEYBOARD_SIZE = KEYBOARD_BUTTON_SIZE[0] * KEYBOARD_BUTTON_PER_ROW + PAD * (KEYBOARD_BUTTON_PER_ROW - 1), \
                    KEYBOARD_BUTTON_SIZE[1] * keyboard_rows + PAD * (keyboard_rows - 1)  # 按钮区域的总大小
    DISPLAY_POSITION = (SCREEN_SIZE[0] - KEYBOARD_SIZE[0]) // 2, SCREEN_SIZE[1] // 10  # 显示输入区域的位置
    display_font = pygame.font.Font(*DISPLAY_FONT)  # 显示输入区域字体
    display_height = display_font.get_height() + 2 * PAD  # 显示输入区域高度

    x, y = DISPLAY_POSITION[0], DISPLAY_POSITION[1] + display_height + PAD  # 按钮区域的位置
    start_x = x
    # 对每个按钮位置进行排列
    for i, button in enumerate(keyboard_button_grp):
        button.rect.topleft = x, y
        if (i + 1) % KEYBOARD_BUTTON_PER_ROW:
            x += KEYBOARD_BUTTON_SIZE[0] + PAD
        else:
            x = start_x
            y += KEYBOARD_BUTTON_SIZE[1] + PAD

    def draw_area_display(screen):
        # 绘显示输入区域
        img = pygame.Surface((KEYBOARD_SIZE[0], display_height)).convert()
        img.fill(DISPLAY_BG_COLOR)
        img.blit(display_font.render(''.join(get_keyboard_input()), True, DISPLAY_TEXT_COLOR), (PAD, PAD))
        screen.blit(img, DISPLAY_POSITION)

    def draw_area_keyboard(screen, keyboard_button_grp):
        # 绘按钮区域
        keyboard_button_grp.draw(screen)

    fps_clock = pygame.time.Clock()
    while True:
        # 判断是否最终输出
        if end_of_input():
            return get_keyboard_input()
        
        mouse_clicked = None
        # 获取 mouse_x, mouse_y, mouse_clicked
        for event in pygame.event.get():
            if event.type == QUIT:
                exit()
            if event.type == MOUSEBUTTONDOWN:
                mouse_clicked = True
            elif event.type == MOUSEBUTTONUP:
                mouse_clicked = False
            elif event.type == MOUSEMOTION:
                mouse_x, mouse_y = event.pos

        screen.fill(BLACK)
        draw_area_display(screen)
        keyboard_button_grp.update(mouse_x, mouse_y, mouse_clicked)
        draw_area_keyboard(screen, keyboard_button_grp)
        fps_clock.tick(FPS)
        pygame.display.update()

2.3. 运行

if __name__ == '__main__':
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE)
    result = keyboard(screen)
    print(result)
    pygame.quit()

3. 结语

这篇文章给大家一个简单的展示如何通过pygame绘制和实现虚拟键盘,当然这里只是实现了简单的打字功能。通过修改 add_input(), 为特殊 id 的 KeyboardButton 定制一些特殊的功能都是可以尝试的。祝大家游戏愉快!

发布了6 篇原创文章 · 获赞 4 · 访问量 978

猜你喜欢

转载自blog.csdn.net/weixin_42487713/article/details/104167605