当前位置: 移动技术网 > 科技>操作系统>windows > Pygame 外星人入侵(9)开始按钮

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

2020年08月10日  | 移动技术网科技  | 我要评论

引言

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

一、定义按钮基类

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

效果如下:
在这里插入图片描述

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

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网