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

引言

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

一、定义按钮基类

由于 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 字体的使用方法,并且掌握了如何通过现有的模块来组织成需要的东西(类似造轮子?)
通过对前面知识的巩固,再加新功能时,就不会感到迷茫,可以马上猜到需要修改的位置,基本上八九不离十。

要在 Pygame 创建一个开始游戏按钮,可以按照以下步骤进行: 1. 创建一个按钮图片,可以使用任何图像编辑器(如 Photoshop 或 GIMP)。按钮图片应该包含常规状态(未选)和悬停状态(鼠标悬停在按钮上)的图像。 2. 在 Pygame 加载按钮图像,并将其绘制到屏幕上。您可以使用 Pygame 的 `pygame.image.load()` 函数来加载图像,然后使用 `pygame.Surface.blit()` 函数将其绘制到屏幕上。 3. 创建一个 Pygame 矩形对象,该对象与按钮图像的位置和大小相匹配。您可以使用 `pygame.Rect()` 函数创建矩形对象,并指定其左上角的位置和宽度/高度。 4. 在主循环,检查鼠标位置是否在按钮矩形内。如果是,则将按钮图像切换到悬停状态,并在单击按钮时执行游戏开始操作。 这是一个简单的示例代码,可以帮助您开始: ```python import pygame # 初始化 Pygame pygame.init() # 设置屏幕大小 screen_width = 800 screen_height = 600 screen = pygame.display.set_mode((screen_width, screen_height)) # 加载按钮图像 button_image = pygame.image.load('button.png') button_rect = button_image.get_rect() # 设置按钮位置 button_rect.centerx = screen_width // 2 button_rect.centery = screen_height // 2 # 主循环 while True: # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN: # 如果鼠标单击了按钮,执行游戏开始操作 if button_rect.collidepoint(event.pos): start_game() # 绘制屏幕 screen.fill((255, 255, 255)) screen.blit(button_image, button_rect) # 更新屏幕 pygame.display.update() ``` 请注意,此示例代码的 `start_game()` 函数是您的游戏开始操作的占位符。您需要将其替换为实际的游戏逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值