Python-项目实战--贪吃蛇小游戏-游戏框架搭建(3)

news2024/12/22 22:06:52

1.游戏框架搭建

  • 介绍pygame开发图像界面游戏的几个要素,并且把贪吃蛇游戏的整体框架搭建完成

  • 本节知识点包括:

  • pygame的初始化和退出

  • 游戏主窗口

  • 游戏循环和游戏时钟

  • 主窗口背景颜色

  • 绘制文本

  • pygame的坐标系

  • 游戏事件监听

  • 绘制图形

  • 定时器事件

1.5绘制文本

  • pygame的font模块中专门提供了一个SysFont类,可以创建系统字体对象,从而能够实现在游戏窗口中绘制文字内容。

  • 要想在游戏窗中绘制文本内容,需要执行以下3个步骤:

  • 创建字体对象

  • 用字体渲染指定的文本内容,并生成一张图像 (Surface 对象)

  • 将生成的图像绘制在游戏主窗口的指定位置

以上三个步骤的示意图如下:

1.5.1创建字体对象

  • SysFont的初始化方法的语法如下:

SysFont(name, size, bold=False, italic=False) -> Font 

其中:

  • 参数

  • name系统字体的名称

注意:可以设置的字体与操作系统有关,通过pygame . font . get_ fonts() 可以获取当前系统的所有可用字体列表

print(pygame.font.get_ fonts())
  • size 字体大小

  • bold 是否粗体,默认为否

  • italic 是否斜体,默认为否

  • 返回

  • Font 对象

代码实现

  • 贪吃蛇游戏中的文字一共有2种颜色,分别是:

  • 分数文字颜色一浅灰色

  • 游戏暂停和结束时的提示文字颜色一深灰色

为了方便后续代码的编写,我们首先在game_items.py 模块的顶部先定义两个字体颜色常量,代码如下:

SCORE_TEXT_COLOR = (192, 192, 192)   # 分数文字颜色
TIP_TEXT_COLOR = (64, 64, 64)        # 提示文字颜色

game_items.py 中定义Lablel类,并且实现初始化方法,代码如下

class Label(object):
    """文字标签类"""
    
    def __init__(self, size =48, is_score=True):
        """初始化标签信息
        :param size 文本的字体大小
        :param is_score 是否显示得分的对象
        """
        self.font = pygame.font.SysFont('simhei', size)
        self.is_score = is_score

1.5.2渲染文本内容

  • 使用创建的字体对象调用render 方法,渲染生成一张图像(Surface 对象), 语法如下:

render(text, antialias, color, background=None) -> Surface

其中:

  • 参数

  • text 文字内容

  • antialias 是否抗锯齿,抗锯齿效果会让绘制的文字看起来更加平滑

  • color 文字颜色

  • background 背景颜色,默认为None

  • 返回

  • Surface 对象,可以理解为一张刚好包含文字内容的图像

  • Surface对象调用get_ rect 方法,可以获得图像大小

1.5.3绘制渲染结果

  • pygame为Surface对象提供了一个blit 方法,可以在一个 Surface对象中绘制另外一个Surface对象的内容。语法如下:

blit(source, dest, area=None, special_ flags = 0) -> Rect

其中:

  • 参数

  • source 要绘制的图像(Surface 对象)

  • dest目标位置

  • 暂时传入(0, 0),有关内容在后续小节介绍

  • 返回

  • Rect 对象,绘制结果对应的矩形区域,有关内容在后续小节介绍

代码实现

  • game_items.py中的Label类中定义draw方法,并接收游戏主窗口作为参数,代码如下:

def draw(self, window, text):
    """绘制当前对象的内容

    :param window: 游戏主窗口
    :param text: 要显示的文本内容
    """
    
    # 使用字体渲染文本内容
    color = SCORE_TEXT_COLOR if self.is_score else TIP_TEXT_COLOR
    text_surface = self.font.render(text, True, color)

    # 在游戏窗口中绘制渲染结果
    window.blit(text_surface, (0, 0))
  • game.py中的start方法中的while循环中加入测试分数的代码

# 绘制得分
self.score += 1
self.score_label.draw(self.main_window, "Denfen:%d" % self.score)

1.5.4测试分数文本的绘制

Label类准备告一段落后,接下来就对Game类进行一个扩展,先在屏幕的左上角位置显示游戏的分数

  • 首先,在game.py中的Game类的初始化方法中,定义两个属性,代码如下:

class Game(object):
    """游戏类"""
    def __init__(self):
        self.main_window = pygame.display.set_mode((640, 480))
        pygame.display.set_caption("贪吃蛇")

        self.score_label = Label()  # 得分的标签
        self.score = 0
  • 然后,在game.py中的Game类的start方法的游戏循环内部,增加代码修改部分并绘制在游戏主窗口,代码如下:

while True:
    # 设置窗口背景颜色
    self.main_window.fill(BACKGROUND_COLOR)

    # 绘制得分
    self.score += 1
    self.score_label.draw(self.main_window, "Denfen:%d" % self.score)
    # 刷新窗口内容
    pygame.display.update()

    # 设置刷新率
    clock.tick(60)

1.5.5阶段性小结

  • 绘制文本内容的3个步骤:

  • pygame.font.SysFont("simhei", size) 创建字体对象

  • self.font.render(self.text, True, color) 使用文字及颜色渲染内容

  • window.blit(text_surface, (0, 0)) window中绘制渲染结果

  • pygame的绘制动作类似于绘制油画——也就是后绘制的内容会叠加在之前绘制内容上

  • 调用完所有绘制方法,一定要调用pygame.display.update()方法,否则无法在屏幕上看到绘制结果

1.6 pygame坐标系

1.6.1pygame的坐标系

  • 坐标系的用处就是以坐标原点为参照,准确地描述出屏幕上的任意位置或者区域。pygame的坐标系定义如下:

  • 坐标原点在游戏窗口的左上角

  • x轴沿水平方向向右,逐渐增加

  • y轴沿垂直方向向下,逐渐增加

如下图所示:

现在,我们回顾一下在上一小节Label类draw方法中的最后一句代码:

# 绘制文本内容到窗口
window.blit(text_surface, (0, 0))

我们给blit方法传递的第二个参数(0, 0),就是指定在游戏窗口的什么位置来绘制文字

1.6.2矩形区域

  • 在游戏中,所有可见的元素都是以矩形区域来描述位置区域的,一个矩形区域包含四个要素: (x, y) (width,height)

  • pygame专门提供了一个类Rect于描述矩形区域。Rect 的初始化方法的语法如下:

Rect(x, y, width, height) -> Rect

知道了矩形区域这个概念之后,接下来我们就做一个实战演练,将得分文字绘制在游戏窗口的左下角。

要实现这一目标,一共需要3个步骤:

  • 利用get _rect获得渲染完成的文本图像(Surface 对象)的矩形区域

  • 通过计算设置文本图像的显示位置

  • 利用Rect提供的属性设置文本图像的显示位置

  • 获得文本图像的矩形区域和位置

修改Label类draw方法代码如下:

def draw(self, window, text):
    """绘制当前对象的内容"""
    # 渲染字体
    color = SCORE_TEXT_COLOR if self.is_score else TIP_TEXT_COLOR
    text_surface = self.font.render(text, True, color)

    # 获取文本的矩形
    text_rect = text_surface.get_rect()
    # print("文字的矩形:", text_rect)

    # 获取窗口的矩形
    window_rect = window.get_rect()

    # 修改显示的坐标
    text_rect.y = window_rect.height - text_rect.height

    # 绘制文本内容到窗口
    window.blit(text_surface, text_rect)
  • 利用Rect的属性设置显示位置

为了方便程序员对矩形区域进行操作,pygame提供了一系列方便的属性。

下表以矩形区域rect = Rect(10, 80, 168, 50)

序号

属性

说明

示例

1

x、left

水平方向和Y轴的距离

rect.x = 10、rect.left = 10

2

y、top

垂直方向和X轴的距离

rect.y = 80、rect.top = 80

3

width、w

宽度

rect.width = 168、 rect.w = 168

4

height、h

高度

rect.height = 50、rect.h = 50

5

right

右侧 = x +w

rect.right =178

6

bottom

底部 = y + h

rect.bottom = 130

7

size

尺寸(w, h)

rect.size = (168, 50)

8

topleft

(x, y)

rect.topleft = (10, 130)

9

bottomleft

(x, bottom)

rect.bottomleft = (10, 130)

10

topright

(right, y)

rect.topright = (178, 80)

11

bottomright

(right, bottom)

rect.bottomright = (178, 130)

12

centerx

中心点x = x + 0.5 * w

rect.centerx = 94

13

centery

中心点y = y + 0.5 * h

rect.centery = 105

14

center

(centerx, centery)

rect.center = (94, 105)

15

midtop

(centerx, y)

rect.midtop = (94, 80)

16

midleft

(x, centery)

rect.midleft = (10, 105)

17

midbottom

(centerx, bottom)

rect.midbottom = (94, 130)

18

midright

(right, centery)

rect.midright = (178, 105)

属性示意图如下:

  • 介绍了Rect的属性之后,我们使用属性来修改一下Label类draw方法

def draw(self, window, text):
    """绘制当前对象的内容"""
    # 渲染字体
    color = SCORE_TEXT_COLOR if self.is_score else TIP_TEXT_COLOR
    text_surface = self.font.render(text, True, color)

    # 获取文本的矩形
    text_rect = text_surface.get_rect()

    # 获取窗口的矩形
    window_rect = window.get_rect()

    # 修改显示的坐标
    text_rect.bottomleft = window_rect.bottomleft

    # 绘制文本内容到窗口
    window.blit(text_surface, text_rect)

1.6.3阶段性小结

  • pygame的坐标原点在窗口的左上角,x水平向右递增,y垂直向下递增

  • 利用Rect对象可以准确地指定游戏窗口上的某一块矩形区域

  • 合理利用Rect提供的属性,在设置矩形区域时会更加方便

1.7游戏事件监听

之前学习了:

游戏循环的主要目的是保证游戏不会立即退出

在游戏循环中,需要做的3件事情,分别是:

  • 绘制游戏元素

  • 每一次执行游戏循环内的代码,游戏窗口中的所有内容都会被绘制

  • 更新显示

  • 只有调用了pygame.diaplay.update()方法,才能在游戏窗口中看到最终的绘制结果

  • 设置刷新帧率

  • 达到流畅的动画效果

  • 降低CPU的负荷

在游戏循环中要需要做的最后一件事 -- 事件监听

1.7.1事件和监听概念

首先,我们来明确2个概念:事件和监听

  • 事件就是游戏启动后,用户针对游戏所做的操作,例如:点击关闭按钮,点击鼠标,按下键盘

  • 监听就是在游戏循环中,判断用户在当前这一时刻,所做的具体操作

  • 提示:只有监听到用户具体的操作,才能有针对性的做出响应

明确了事件监听的概念后,我们来看一下游戏循环内部的工作示意图:

通过示意图,可以很直观地看到,只有:

  • 监听到退出事件,才能实现用户点击关闭按钮时终止游戏的效果

  • 监听到键盘按键事件

  • 才能在用户按下方向键后,改变贪吃蛇的运动方向

  • 才能在用户按下空格后

  • 如果本轮游戏没有结束,则暂停或者继续游戏

  • 如果本轮游戏已经结束,则开启新一轮游戏

1.7.2 pygame监听事件

pygame专门提供了一个event模块用于处理游戏事件,通过pygame.event.get()方法可以获得当前这一时刻发生的所有事件列表

提示:同一时刻,可能会发生很多事件!例如,在 用户按下方向键修改贪吃蛇方向的同时, 定时器事件被触发了,此时还需要让 贪吃蛇向前移动

首先演练一下对退出事件的监听和处理。找到game.py中的Game类的start方法,对代码调整如下:

def start(self):
    """启动并控制游戏"""
    clock = pygame.time.Clock() # 游戏时钟

    while True:

        # 事件监听
        for event in pygame.event.get():  # 遍历同一时刻发生的事件列表
            if event.type == pygame.QUIT: # 判断退出事件
                print("点击了关闭按钮")
                return

        # 设置窗口背景颜色
        self.main_window.fill(BACKGROUND_COLOR)

然后,再来监听一下用户按键事件,就是按下ESC键时同样能够直接退出游戏。对game.py中的Game类的start方法的代码调整如下:

def start(self):
    """启动并控制游戏"""
    clock = pygame.time.Clock()

    while True:

        # 事件监听
        for event in pygame.event.get():  # 遍历同一时刻发生的事件列表
            if event.type == pygame.QUIT: # 判断退出事件
                print("点击了关闭按钮")
                return

            elif event.type == pygame.KEYDOWN:

                if event.key == pygame.K_ESCAPE:
                    print("按下了ESC键")
                    return


        # 设置窗口背景颜色
        self.main_window.fill(BACKGROUND_COLOR)

1.7.3游戏状态切换和提示

  • 按照贪吃蛇的游戏规则描述,空格键可以改变游戏的状态:

  • 一局游戏结束后,按下空格键可以重新开启一局新游戏

  • 游戏过程中按下空格键,可以暂停游戏;再次按下空格键,可以继续游戏

  • 要实现游戏状态的切换,我们分两步来完成:

  • 创建提示标签游戏状态标记游戏状态不同显示不同的提示信息

  • 监听空格键按键,并根据当前游戏状态标记,修改游戏状态

提示标签和状态标记

  • 修改game.py中Game类的初始化方法,创建提示标签和游戏状态标记,代码如下:

def __init__(self):
    self.main_window = pygame.display.set_mode((640, 480))
    pygame.display.set_caption("贪吃蛇")

    self.score_label = Label()  # 得分的标签
    self.score = 0

    self.tip_label = Label(24, False)  # 暂停和游戏结束的提示标签

    self.is_game_over = False  # 游戏是否结束的标记,如果为True, 则说明游戏已经结束
    self.is_pause = False  # 游戏是否暂停的标记,如果为True,则说明游戏已经被暂停 
  • 修改game.py中的Game类中的start方法中的游戏循环中的代码,在游戏暂停和游戏结束时,显示不同的信息,并且只有在既不是暂停也没有结束时,才修改游戏得分,代码如下:

# 设置窗口背景颜色
self.main_window.fill(BACKGROUND_COLOR)

# 绘制得分
self.score_label.draw(self.main_window, "DeFen: %d" % self.score)

# 绘制暂停、游戏结束的标签
if self.is_game_over:
    self.tip_label.draw(self.main_window, "Youxi Jiesu anKonggeJian KaiQi xinyouxi")
elif self.is_pause:
    self.tip_label.draw(self.main_window, "Youxi Zanting KonggejianJixu...")
else:
    self.score += 1


# 刷新窗口内容
pygame.display.update()
  • 修改game_items.py中的Label类中的draw方法,将提示标签的文字显示在游戏窗口的中间位置,代码如下:

def draw(self, window, text):
    """绘制当前对象的内容"""
    # 渲染字体
    color = SCORE_TEXT_COLOR if self.is_score else TIP_TEXT_COLOR
    text_surface = self.font.render(text, True, color)

    # 获取文本的矩形
    text_rect = text_surface.get_rect()

    # 获取窗口的矩形
    window_rect = window.get_rect()

    # 修改显示的坐标
    if self.is_score:
        # 游戏得分,显示在窗口左下角
        text_rect.bottomleft = window_rect.bottomleft
    else:
        # 提示信息,暂停,游戏结束,显示在窗口中间
        text_rect.center = window_rect.center


    # 绘制文本内容到窗口
    window.blit(text_surface, text_rect)

监听空格键按键

  • 修改game.py中的Game类中的start方法中的游戏循环中的代码,并根据当前游戏状态标记,修改游戏状态

def start(self):
    """启动并控制游戏"""
    clock = pygame.time.Clock()

    while True:

        # 事件监听
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # print("点击了关闭按钮")
                return

            elif event.type == pygame.KEYDOWN:

                if event.key == pygame.K_ESCAPE:
                    # print("按下了ESC键")
                    return

                elif event.key == pygame.K_SPACE:
                    if self.is_game_over:
                        self.reset_game()
                    else:
                        self.is_pause = not self.is_pause

        # 设置窗口背景颜色
        self.main_window.fill(BACKGROUND_COLOR)

1.7.4阶段性小结

  • 游戏循环中需要做4件事情

  • 事件监听

  • 绘制游戏元素

  • 更新显示

  • 设置刷新帧率

  • 同一时刻,可能会发生多个事件,因此应该使用for遍历事件列表

  • 使用event.type可以判断事件的类型,如:退出事件,按键事件

  • 如果是按键事件,使用event.key可以判断具体的按键

1.8绘制图形

  • pygame的draw模块中专门提供了一系列方法,可以方便地绘制图形。

  • 常用的绘制图形方法如下:

序号

语法

说明

1

rect(Surface, color, Rect, width=0) -> Rect

绘制矩形,width > 0则绘制边框

2

ellipse(Surface, color, Rect, width=0) -> Rect

绘制与Rect内切的椭圆,width同上

3

line(Surface, color, start_ pos, end_pos, width=1) ->Rect

绘制从start_pos到end _pos的线条

4

lines(Surface,color, closed, pointlist, width=1) ->Rect

绘制多个线条,closed 设置首尾相连

  • 在这一小节,我们就利用draw模块提供的ellipse方法实现食物的绘制工作。

要实现这一目标,一共需要3个步骤:

  • 在屏幕的左上角绘制一个圆形表示食物

  • 让食物随机出现

  • 增加食物出场动画

1.8.1简单绘制食物

首先,在game_items.py模块中定义屏幕矩形区域小格子大小的全局常量,之所以要定义全局常量是因为:

  • 定义屏幕矩形区域是为了方便后续计算食物的位置以及蛇身体的位置

  • 在贪吃蛇游戏中,我们可以把屏幕矩形区域划分成若干个小格子

  • 每一个小格子中,可以显示一个食物或者一节蛇的身体

定义全局常量的代码如下:

  • game_items.py的顶部定义全局变量:

# 全局变量的定义
SCREEN_RECT = (0, 0, 640, 480)       # 窗口的大小
CELL_SIZE = 20                       # 每一个格子的宽高
  • game_items.py模块的末尾,定义Food类,并实现如下代码:

class Food(object):
    """食物类"""

    def __init__(self):
        """初始化食物"""
        self.color = (255, 0, 0)  # 颜色初始为 红色
        self.score = 10  # 默认得分为10分
        self.rect = (0, 0, CELL_SIZE, CELL_SIZE)  # 初始的显示位置

    def draw(self, window):
        """使用当前食物的矩形,绘制实心圆形"""
        pygame.draw.ellipse(window, self.color, self.rect)

1.8.2随机食物位置

  • game_items.py的顶部导入random模块,以方便使用随机数,代码如下:

import random
  • game_items.py模块的Food类中定义random_rect方法,随机确定游戏窗口的任一小格子设置食物出现的位置,实现如下代码:

class Food(object):
    """食物类"""

    def __init__(self):
        """初始化食物"""
        self.color = (255, 0, 0)  # 颜色初始为 红色
        self.score = 10  # 默认得分为10分
        self.rect = (0, 0, CELL_SIZE, CELL_SIZE)  # 初始的显示位置

        # 初始化食物随机分配一个位置
        self.random_rect()

    def draw(self, window):
        """使用当前食物的矩形,绘制实心圆形"""
        pygame.draw.ellipse(window, self.color, self.rect)

    def random_rect(self):
        """随机确定绘制食物的位置"""
        # 计算可用的行数和列数
        col = SCREEN_RECT.w / CELL_SIZE - 1
        row = SCREEN_RECT.h / CELL_SIZE - 1

        # 随机分配一个行和列,并计算行和列的x,y值
        x = random.randint(0, col) * CELL_SIZE  # 屏幕上小格子的列数
        y = random.randint(0, row) * CELL_SIZE  # 屏幕上小格子的行数

        # 重新生成绘制食物的矩形
        self.rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)
  • 修改game.pyGame类reset_game方法,在游戏复位时,重新设置食物的位置,代码如下:

  def reset_game(self):
    """重置游戏参数"""
    self.score = 0
    self.is_game_over = False
    self.is_pause = False

1.8.3食物出现动画

  • 通过之前小节的学习,我们已经知道,游戏循环体中的代码执行频率是每秒60帧,这样做的目的之一是为了达到非常连续、高品质的动画效果

  • 在实际开发中,我们只需要让连续帧绘制的结果相差不大,这样就能够在视觉上产生连续的动画效果。如下图所示:

  • pygame在Rect类中提供了2个方法inflate和inflate_ip,可以非常方便地实现食物由小变大的动画效果,语法如下:

inflate(x, y) -> Rect 
inflate_ip(x, y) -> None
  • inflate和inflate _ip方法都可以以矩形区域的中心点为中心,向四周扩大或缩小,其中:

  • x表示水平方向缩放的像素,正数放大,负数缩小

  • y表示垂直方向缩放的像素,正数放大,负数缩小

注意: x和y必须要是偶数,例如传入-2,表示左边减少-个像素, 右边同样减少1个像素。
  • inflate和inflate_ ip方法的区别是:

  • inflate返回一个新的Rect对象,不会修改调用Rect对象的属性

  • inflate_ip不返回新的Rect对象,会修改调用Rect对象的属性

现在,我们就利用inflate方法来实现一下食物在出现时,由小变大的动画效果

  • 首先,在game_items.pyFood类中的random_rect方法中,设置食物大小的初始矩形区域,代码如下:

def random_rect(self):
    """随机确定绘制食物的位置"""
    # 计算可用的行数和列数
    col = SCREEN_RECT.w / CELL_SIZE - 1
    row = SCREEN_RECT.h / CELL_SIZE - 1

    # 随机分配一个行和列,并计算行和列的x,y值
    x = random.randint(0, col) * CELL_SIZE
    y = random.randint(0, row) * CELL_SIZE

    # 重新生成绘制食物的矩形
    self.rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)
    self.rect.inflate_ip(-CELL_SIZE, -CELL_SIZE)  # 把创建好的矩形大小修改为0
  • 然后,在game_items.pyFood类中修改draw方法,在绘制食物前,判断一下食物的矩形区域宽度,如果还没有和小格子宽度一致,则向四周放大,代码如下:

def draw(self, window):
    """使用当前食物的矩形,绘制实心圆形"""
    if self.rect.w < CELL_SIZE: # 只要显示的矩形还小于单元格大小,就继续放大
        self.rect.inflate_ip(2, 2) # 向四周各自放大1个像素

    pygame.draw.ellipse(window, self.color, self.rect)

1.8.4阶段性小节

  • draw模块提供了一系列方法,可以方便地绘制图形:

  • rect绘制矩形

  • ellipse绘制椭圆

  • 定义SCREEN_RECT和CELL_SIZE常量可以方便计算食物的出现位置

  • inflate和iflate_ip方法可以方便地缩放矩形,参数务必是偶数

  • 在游戏循环中,每一帧绘制的结果相差不大,在视觉上就会产生一个连续播放的动画效果

1.9定时器事件

  • 按照贪吃蛇的游戏规则描述,如果食物出现的30秒内,贪吃蛇没有吃到食物,那么:

  • 没有被吃到的食物从屏幕上消失

  • 在游戏窗口的其他任一随机位置再次出现新的食物

  • 现在如果暂时不考虑贪吃蛇吃食物的情况,要实现游戏规则的需求,我们只需要每隔30秒让食物对象调用一下game_items.py Food类的random_rect方法即可。

  • 这种每隔一段时间,复执行一个固定动作的场景,我们可以使用定时器事件来实现。pygame 的time模块中提供的set_ timer方法,就是专门]用来定义定时器事件的。

  • 要定义定时器事件,一共需要 3个步骤:

  • 定义定时器事件代号常量

  • 使用set _timer 方法设置定时器事件

  • 游戏循环监听定时器事件

1.9.1设置定时器事件

  • 首先,在game_items.py模块中定义定时器事件常量,代码如下

FOOD_UPDATE_EVENT = pygame.USEREVENT        # 食物更新标志

提示:

  • 事件代号是一个整数,初始值可以使用pygame.USEREVENT

  • 如果要定义多个事件代号,可以从pygame.USEREVENT开始顺序递增

  • 然后,在game.items.py中的Food类中的random_rect的末尾,设置定时器事件,代码如下:

def random_rect(self):
        """随机确定绘制食物的位置"""
        # 计算可用的行数和列数
        col = SCREEN_RECT.w / CELL_SIZE - 1
        row = SCREEN_RECT.h / CELL_SIZE - 1

        # 随机分配一个行和列,并计算行和列的x,y值
        x = random.randint(0, col) * CELL_SIZE
        y = random.randint(0, row) * CELL_SIZE

        # 重新生成绘制食物的矩形
        self.rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)
        self.rect.inflate_ip(-CELL_SIZE, -CELL_SIZE)  # 把创建好的矩形大小修改为0

        # 设置定时,时间到了之后要重新设置食物位置
        pygame.time.set_timer(FOOD_UPDATE_EVENT, 30000)

1.9.2监听定时器事件

  • game.pyGame类中的start方法中的游戏循环中,增加更新食物事件监听,代码如下:

def start(self):
    """启动并控制游戏"""
    clock = pygame.time.Clock()

    while True:

        # 事件监听
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # print("点击了关闭按钮")
                return

            elif event.type == pygame.KEYDOWN:

                if event.key == pygame.K_ESCAPE:
                    # print("按下了ESC键")
                    return

                elif event.key == pygame.K_SPACE:
                    if self.is_game_over:
                        self.reset_game()
                    else:
                        self.is_pause = not self.is_pause

            if not self.is_pause and not self.is_game_over:
                # 只有当游戏没有暂停也没有结束才需要处理
                if event.type == FOOD_UPDATE_EVENT:
                    # 更新食物位置
                    self.food.random_rect()

内容总结于:https://space.bilibili.com/441640380

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/350986.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nuclei文*件上*传FUZZ POC

目录 1.前言 2. Nuclei文件上传FUZZ POC 3. 实战中的应用 1.前言 该文件上传FUZZ POC主要来源于一个靶*场,该POC 主要用来FUZZ目标js页面中的upload ajax请求,以此来进一步尝试文件上传漏*洞利*用。 这里也要感谢下“打工仔1号”提供的开*发人员常见的文*件上*传javaScr…

设计模式(九)----结构型模式之代理模式

一、结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制或者实现机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满…

数字孪生|可视化图表之堆叠柱状图

一、含义 堆叠柱状图&#xff08;Stacked Bar Chart&#xff09;将每个柱子进行分割以显示相同类型下各个数据的大小情况&#xff0c;它将多个数据集的柱子彼此叠加显示&#xff0c;适合用来显示大类别如何细分为较小的类别&#xff0c;以及每部分与总量之间的关系。在展示不同…

Lecture5 实现线性回归(Linear Regression with PyTorch)

目录 1 Pytorch实现线性回归 1.1 实现思路 1.2 完整代码 2 各部分代码逐行详解 2.1 准备数据集 2.2 设计模型 2.2.1 代码 2.2.2 代码逐行详解 2.2.3 疑难点解答 2.3 构建损失函数和优化器 2.4 训练周期 2.5 测试结果 3 线性回归中常用优化器 1 Pytorch实现线性回归…

网络协议(七):传输层-UDP

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 网络协议(三)&#xff1a;路由器原理及数据包传输过程 网络协议(四)&#xff1a;网络分类、ISP、上网方式、公网私网、NAT 网络…

06- 信用卡反欺诈 (机器学习集成算法) (项目六)

本项目为 kaggle 项目 项目难点在于: 盗刷的比例占总数据量的比例较低, 直接预测为非盗刷也有 99.8% 的准确率.data.info() # 查看所有信息msno.matrix(data) # 查看缺失值axis1 时 # 删除列显示颜色种类 from matplotlib import colors plt.colormaps() # mag…

关于知识图谱TransR

论文题目 Learning Entity and Relation Embeddings for Knowledge Graph Completion 论文链接 TransR 文中指出&#xff0c;不管是TransE还是TransH都是将实体和关系映射同一空间&#xff0c;但是&#xff0c;一个实体可能具有多个层面的信息&#xff0c;不同的关系可能关注…

ray简单介绍

ray使用也有一段时间了, 这篇文章总结下ray的使用场景和用法 ray可以做什么? 总结就两点: 可以将其视为一个进程池(当然不仅限于此), 可以用于开发并发应用还可以将应用改造为分布式 基于以上两点, 有人称之为:Modern Parallel and Distributed Python 构成 Ray AI Runtim…

Redis多级缓存

文章目录一. 什么是多级缓存二. JVM进程缓存一. 什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能…

Linux高级IO

文章目录一、五种 IO 模型1.阻塞 IO2.非阻塞 IO3.信号驱动 IO4. IO 多路转接5.异步 IO二、高级 IO 重要概念1.同步通信和异步通信2.阻塞和非阻塞fcntl 系统调用3.其他高级 IO三、I/O 多路转接之 select1.函数原型socket 就绪的条件2.理解 select 的执行过程3.使用示例4. select…

新手小白如何入门黑客技术?

你是否对黑客技术感兴趣呢&#xff1f;感觉成为黑客是一件很酷的事。那么作为新手小白&#xff0c;我们该如何入门黑客技术&#xff0c;黑客技术又是学什么呢&#xff1f; 其实不管你想在哪个新的领域里有所收获&#xff0c;你需要考虑以下几个问题&#xff1a; 首先&#xff…

Springboot扩展点之FactoryBean

前言FactoryBean是一个有意思&#xff0c;且非常重要的扩展点&#xff0c;之所以说是有意思&#xff0c;是因为它老是被拿来与另一个名字比较类似的BeanFactory来比较&#xff0c;特别是在面试当中&#xff0c;动不动就问你&#xff1a;你了解Beanfactory和FactoryBean的区别吗…

spring cloud gateway网关和链路监控

文章目录 目录 文章目录 前言 一、网关 1.1 gateway介绍 1.2 如何使用gateway 1.3 网关优化 1.4自定义断言和过滤器 1.4.1 自定义断言 二、Sleuth--链路追踪 2.1 链路追踪介绍 2.2 Sleuth介绍 2.3 使用 2.4 Zipkin的集成 2.5 使用可视化zipkin来监控微服务 总结 前言 一、网关…

ubuntu wordpress建站

nginx 安装测试 https://blog.csdn.net/leon_zeng0/article/details/113578143 ubuntu 基于apache2安装wordpress https://ubuntu.com/tutorials/install-and-configure-wordpress#7-configure-wordpress 报错403的话&#xff0c;是权限没搞对&#xff0c;解决参考https://ww…

空间误差分析:统一的应用导向处理(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

深度学习算法面试常问问题(二)

X86和ARM架构在深度学习侧的区别&#xff1f; X86和ARM架构分别应用于PC端和低功耗嵌入式设备&#xff0c;X86指令集很复杂&#xff0c;一条很长的指令就可以完成很多功能&#xff1b;而ARM指令集很精简&#xff0c;需要几条精简的短指令完成很多功能。 影响模型推理速度的因…

mysql分库分表概念及原理、ShardingSphere实现mysql集群分库分表读写分离

一&#xff1a;分库分表概念 1.1 为什么要对数据库进行分表 索引的极限&#xff1a;单表数据量达到几十万或上百万以上&#xff0c;使用索引性能提升也不明显。 分表使用门槛&#xff1a;单表行数超过 500 万行或者单表容量超过 2GB&#xff0c;才推荐进行分库分表。 分表适用…

MIT 6.S965 韩松课程 04

Lecture 04: Pruning and Sparsity (Part II) 文章目录Lecture 04: Pruning and Sparsity (Part II)剪枝率分析每层的敏感度自动剪枝微调和训练稀疏网络彩票假说稀疏度的系统支持不均衡负载M:N 稀疏度本讲座提纲章节 1&#xff1a;剪枝率分析每层的敏感度AMC: AutoML for Model…

C#:Krypton控件使用方法详解(第四讲) ——kryptonLabel

今天介绍的Krypton控件中的kryptonLabel&#xff0c;下面开始介绍这个控件的属性&#xff1a;首先介绍控件中的外观属性&#xff1a;Cursor属性&#xff1a;表示功能为鼠标移动过这个控件的时候显示光标的类型。Text属性&#xff1a;表示显示的文本内容。其他属性不做过多的介绍…

编写 Cypher 代码续

编写 Cypher 代码 过滤查询 查看图中的唯一性约束索引 SHOW CONSTRAINTS查看图中关系的属性类型 CALL db.schema.relTypeProperties()查看图中节点的属性类型 CALL db.schema.nodeTypeProperties()查看数据模型 CALL db.schema.visualization()用 WHERE 子句添加过滤条件 查询执…