欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

Pygame 外星人入侵(9)开始按钮

程序员文章站 2022-03-23 15:34:46
目录引言一、定义按钮基类1、按钮的构成2、在按钮上渲染文本3、将按钮和文本“组合”二、绘制开始按钮1、修改游戏设置2、创建开始按钮实例3、修改绘制屏幕方法三、游戏开始和游戏失败时开启游戏1、检测玩家点击按钮的事件2、点击开始按钮后的业务3、修改主模块逻辑四、小结引言直到上一篇博文为止,我们实现了《外星人入侵》这款有中飞船、外星人、子弹的绘制和移动,以及它们之间的碰撞检测。在这篇博文中,将要实现为游戏增加“开始按钮”。一、定义按钮基类由于 pygame 不提供原生的按钮类供我们使用,因此我们需要自己...

引言

直到上一篇博文为止,我们实现了《外星人入侵》这款有中飞船、外星人、子弹的绘制和移动,以及它们之间的碰撞检测。
在这篇博文中,将要实现为游戏增加“开始按钮”。

一、定义按钮基类

由于 pygame 不提供原生的按钮类供我们使用,因此我们需要自己来定义一个按钮类,以便创建“开始按钮”。
我们新建一个模块 button.py ,在其中定义 Button 类

1、按钮的构成

我们自己定义的按钮由这么两部分构成:
1、作为按钮整体的一个矩形
2、按钮上的文本

而再细分成类的属性的话,可以这么分:
1、按钮整体的尺寸
2、按钮整体的颜色
3、文本的字体
4、文本的颜色
5、按钮的位置
6、文本的内容

# 按钮的基类,我们可以通过实例化按钮类来创建各种按钮
class Button():
    # 初始化按钮
    def __init__(self, settings, screen, msg):
        self.screen = screen
        self.screen_rect = self.screen.get_rect()
        self.settings = settings
        # 设置按钮的尺寸
        self.width = 200
        self.height = 50
        # 设置按钮的颜色
        self.button_color = (0, 255, 0)
        # 设置文本的颜色
        self.text_color = (255, 255, 255)
        # 设置文本的字体
        self.font = pygame.font.Font(None, 48)
        # 设置按钮的位置
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        # 将按钮设置到屏幕中间
        self.rect.center = self.screen_rect.center
        # 将文本渲染成 Surface对象
        self.prep_msg(msg)

2、在按钮上渲染文本

这里值得注意的是:
pygame 没有直接将字符串渲染到 Surface对象上的方法,所以我们必须将字符串转换成 Surface对象,然后将这个 Surface对象(文本)渲染到另一个 Surface对象(按钮)上。
这里是通过 prep_msg() 方法来实现将字符串转换成 Surface对象的

    def prep_msg(self, msg):
        # 将文本字符串渲染成一个Surface对象
        self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
        # 获取文本的坐标
        self.msg_rect = self.msg_image.get_rect()
        # 将文本位置放到按钮中间
        self.msg_rect.center = self.rect.center

其中,pygame 包中的 font 模块的 render 函数将文本转换成 Sruface对象,第二个参数是反锯齿功能,第三个参数是文本颜色,第四个参数是背景颜色。

3、将按钮和文本“组合”

代码写到这里,其实已经可以发现,我们的按钮实际上是绘制出来的一个矩形图案,而按钮上的字实际上是一个由字符串渲染成的 Surface对象
现在,我们如何将两者“组合”成我们希望的完整按钮呢?

其实很简单,就是我们现在游戏屏幕的指定位置上绘制按钮矩形,然后再在矩形上绘制文本即可。
我们将这个方法定义在 Button 类中

    def draw_button(self):
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_rect)

至此,我们就有了一个按钮基类,可以通过它来创建各种不同的按钮,但在《外星人入侵》中,我们只需要一个“开始按钮”。

二、绘制开始按钮

我们想要在运行游戏之初先显示“开始按钮”,然后游戏才开始正常进行。
因此,我们需要将游戏状态的初始值修改为 False,代表着运行之初游戏是处于非活跃状态的

1、修改游戏设置

class GameStats():
    # 初始化游戏状态,设置玩家开局将有多少架飞船可以使用
    def __init__(self, settings):
        self.settings = settings
        self.reset_stats()

    def reset_stats(self):
        self.ship_left = self.settings.ship_limit
        # 游戏刚开始时,处于非活跃状态
        self.game_active = False

2、创建开始按钮实例

我们在主模块中导入 Button 类,并且在游戏主逻辑前创建一个 Button实例,作为我们的开始按钮

# 从 按钮模块 中导入 Button 类
from button import Button
...
def run_game():
	...
	# 创建一个 启动游戏 的按钮
    play_button = Button(my_settings, my_screen, 'Play')
    ...

3、修改绘制屏幕方法

此时,我们在绘制游戏元素之外,还需要绘制刚才创建的开始按钮,因此,需要修改 update_screen() 方法

def update_screen(screen, setting, ship, bullets, aliens, game_stats, button):
    # 为纯黑的游戏屏幕填充上不一样的颜色
    screen.fill(setting.background_color)

    # 在背景之上绘制我们的飞船,注意这里的逻辑,必须是飞船在背景之后绘制,确保飞船在背景的上层
    ship.blitme()

    # 在屏幕和飞船之上,绘制子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    # 在屏幕上绘制外星人
    aliens.draw(screen)

    # 如果游戏处于非活跃状态,那么就绘制按钮
    if not game_stats.game_active:
        button.draw_button()

    # 刷新屏幕,使得元素能够不断刷新位置
    pygame.display.flip()

效果如下:
Pygame 外星人入侵(9)开始按钮

三、游戏开始和游戏失败时开启游戏

现在,我们有了一个显示在屏幕中间的开始按钮。但它只是一个简单的矩形图案,没有任何实质性的作用。

1、检测玩家点击按钮的事件

pygame 的事件包括点击鼠标的行为,所以我们可以在事件检测方法中新增玩家标记鼠标的检测

# 当玩家 点击鼠标 发出事件时
        elif event.type == pygame.MOUSEBUTTONDOWN:
            # 获取玩家鼠标点击的位置
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(mouse_x, mouse_y, play_button, game_stats, aliens, bullets, settings, screen, ship)

当检测到玩家点击了鼠标后,我们需要获取玩家点击的位置信息,并且判断这个位置是否在开始按钮内。
通过 pygame 包的 mouse 模块的 get_pos() 方法来获取玩家鼠标的位置。

2、点击开始按钮后的业务

当玩家点击的是开始按钮时,我们需要考虑游戏需要做什么
1、如果游戏处于非活跃状态,那么就转换成活跃
2、重置游戏设置,主要是让玩家可以重启游戏
3、清空外星人和子弹、生成一群新的外星人、将飞船置于屏幕底部中间。

这些业务统一封装到一个函数中,在检测到玩家点击开始按钮后调用

# 玩家点击Play按钮后开始新游戏
def check_play_button(mouse_x, mouse_y, play_button, game_stats, aliens, bullets, settings, screen, ship):
    button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
    # 当玩家在游戏处于非活跃状态下点击Play按钮时
    if button_clicked and not game_stats.game_active:
        # 游戏活跃时隐藏光标
        pygame.mouse.set_visible(False)
        # 重置游戏设置
        game_stats.reset_stats()
        # 将游戏切换回活跃状态
        game_stats.game_active = True
        # 清空子弹和外星人
        aliens.empty()
        bullets.empty()
        # 创建一群新的外星人,并让飞船居中
        create_fleet(settings, screen, aliens, ship)
        ship.center_ship()

其中,我们还设置了当游戏活跃性为 True 时,玩家的光标不可见的效果。
只有当活跃性为 False 时,玩家才可以看到自己的光标。

3、修改主模块逻辑

由于我们将游戏设置的活跃性初始值改成了 False
所以当游戏开始时,有些事情就不需要做了,这些事包括:
1、飞船的绘制
2、子弹的绘制
3、外星人群的生成

即使游戏没开始也要一直做的事有:
1、事件检测
2、绘制游戏屏幕和开始按钮

因此,我们需要修改一下游戏主循环

# 游戏主循环,使得循环中的代码可以不断循环执行
    while True:
        # 事件检测,现在我们已经将事件循环的代码封装到函数中了,直接运行即可
        check_events(my_ship, my_screen, my_settings, bullets, play_button, game_stats, aliens)

        # 绘制游戏画面,包括屏幕背景、飞船,并将内容显示到游戏屏幕上
        update_screen(my_screen, my_settings, my_ship, bullets, aliens, game_stats, play_button)

        # 当游戏处于活跃状态时,才渲染屏幕元素
        if game_stats.game_active:

            # 每次执行完事件检测循环后,都更新飞船的位置
            my_ship.update()

            # 每次执行完事件检测循环后,都更新子弹的位置、并删除出界的子弹,检测子弹和外星人之间的碰撞
            update_bullet(bullets, my_settings, aliens, my_screen, my_ship)

            # 每次执行完事件检测后,都更新外星人的位置,检测外星人和飞船之间的碰撞
            update_aliens(aliens, my_settings, my_ship, game_stats, bullets, my_screen)

此时,我们运行游戏,可以先看到一个开始按钮,当玩家点击按钮后,才会开始游戏。
当玩家的3架飞船都用完时,会重新跳出开始按钮,玩家再次点击可以重开游戏。

四、小结

至此,我们实现了开始按钮的绘制,并通过玩家点击开始按钮来实现游戏流程的控制。
这里学到了 pygame 字体的使用方法,并且掌握了如何通过现有的模块来组织成需要的东西(类似造*?)
通过对前面知识的巩固,再加新功能时,就不会感到迷茫,可以马上猜到需要修改的位置,基本上八九不离十。

本文地址:https://blog.csdn.net/qq_32740521/article/details/107871553