PyGame:Python 游戏编程入门-1

Posted 苏州程序大白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyGame:Python 游戏编程入门-1相关的知识,希望对你有一定的参考价值。

PyGame:Python 游戏编程入门

✨博主介绍

💂 个人主页:苏州程序大白

💂 个人社区:CSDN全国各地程序猿

🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室,2021年注册苏州凯捷智能科技有限公司

💅 有任何问题欢迎私信,看到会及时回复

👤 微信号:stbsl6,微信公众号:苏州程序大白

💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)

🎯 想加入技术交流群的可以加我好友,群里会分享学习资料

前言


pygame是SDL 库的 Python 包装器,它代表Simple DirectMedia 层。SDL 提供对系统底层多媒体硬件组件(例如声音、视频、鼠标、键盘和操纵杆)的跨平台访问。作为停滞不前的PySDL 项目pygame的替代品开始了生活。SDL 的跨平台特性意味着您可以为支持它们的每个平台编写游戏和丰富的多媒体 Python 程序!pygame

要pygame在您的平台上安装,请使用适当的pip命令:

$ pip install pygame

您可以通过加载库附带的示例之一来验证安装:

$ python3 -m pygame.examples.aliens

如果出现游戏窗口,则pygame说明安装正确!

基本 PyGame 程序

在深入细节之前,让我们先来看看一个基本pygame程序。这个程序创建一个窗口,用白色填充背景,并在它的中间画一个蓝色圆圈:

# Simple pygame program

# Import and initialize the pygame library
import pygame
pygame.init()

# Set up the drawing window
screen = pygame.display.set_mode([500, 500])

# Run until the user asks to quit
running = True
while running:

    # Did the user click the window close button?
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # Fill the background with white
    screen.fill((255, 255, 255))

    # Draw a solid blue circle in the center
    pygame.draw.circle(screen, (0, 0, 255), (250, 250), 75)

    # Flip the display
    pygame.display.flip()

# Done! Time to quit.
pygame.quit()

当你运行这个程序时,你会看到一个如下所示的窗口:


让我们逐段分解这段代码:

  • 第 4 行和第 5 行导入并初始化pygame库。没有这些行,就没有pygame.

  • 第 8 行设置程序的显示窗口。您提供一个列表或一个元组来指定要创建的窗口的宽度和高度。这个程序使用一个列表来创建一个每边 500 像素的方形窗口。

  • 第 11 行和第 12 行设置了一个游戏循环来控制程序何时结束。您将在本教程后面介绍游戏循环。

  • 第 15 到 17 行扫描并处理游戏循环中的事件。您稍后也会参加活动。在这种情况下,唯一处理的事件是pygame.QUIT,当用户单击窗口关闭按钮时发生。

  • 第 20 行用纯色填充窗口。screen.fill()接受指定颜色的 RGB 值的列表或元组。由于(255, 255, 255)提供,窗口充满了白色。

  • 第 23行在窗口中画了一个圆,使用以下参数:

screen:绘制的窗口
(0, 0, 255):一个包含 RGB 颜色值的元组
(250, 250):指定圆心坐标的元组
75:要绘制的圆的半径(以像素为单位)
  • 第 26行将显示的内容更新到屏幕上。没有这个调用,窗口中不会出现任何内容!

  • 29号线出口pygame。这仅在循环完成后发生。

这就是pygame“Hello, World”的版本。现在让我们更深入地研究一下这段代码背后的概念。

PyGame 概念

由于pygameSDL 库可跨不同平台和设备进行移植,因此它们都需要为各种硬件现实定义和使用抽象。了解这些概念和抽象将帮助您设计和开发自己的游戏。

PyGame初始化和模块

该pygame库由许多 Python 结构组成,其中包括几个不同的模块。这些模块提供对系统上特定硬件的抽象访问,以及使用该硬件的统一方法。例如,display允许统一访问您的视频显示,同时joystick允许抽象控制您的操纵杆。

在上面示例中导入pygame库后,您做的第一件事就是使用pygame.init() 。此函数调用所有包含模块的单独init()函数。pygame由于这些模块是对特定硬件的抽象,因此需要此初始化步骤,以便您可以在 Linux、Windows 和 Mac 上使用相同的代码。

显示器和表面

除了模块之外,pygame还包括几个 Python类,它们封装了非硬件依赖的概念。其中之一是Surface最基本的,它定义了一个可以绘制的矩形区域。Surface对象在pygame. 稍后您将看到如何将图像加载到 a 中Surface并将其显示在屏幕上。

在pygame中,所有内容都在单个用户创建的 中查看display,可以是窗口或全屏。显示是使用创建的.set_mode(),它返回一个Surface表示窗口可见部分的值。这是Surface你传递给绘图函数之类pygame.draw.circle()的,当你调用时,它的内容Surface被推送到显示器pygame.display.flip()

图像和矩形

您的基本pygame程序直接在显示器上绘制了一个形状Surface,但您也可以处理磁盘上的图像。该image模块允许您以各种流行的格式加载和保存图像。图像被加载到Surface对象中,然后可以以多种方式进行操作和显示。

如上所述,Surface对象由矩形表示,pygame就像图像和窗口中的许多其他对象一样。矩形被大量使用,以至于有一个特殊的Rect类来处理它们。您将Rect在游戏中使用对象和图像来绘制玩家和敌人,并管理他们之间的碰撞。

好了,理论就讲这么多。让我们设计和编写游戏!

基本游戏设计

导入和初始化 PyGame

导入后pygame,您还需要对其进行初始化。这允许pygame将其抽象连接到您的特定硬件:

# Import the pygame module
import pygame

# Import pygame.locals for easier access to key coordinates
# Updated to conform to flake8 and black standards
from pygame.locals import (
    K_UP,
    K_DOWN,
    K_LEFT,
    K_RIGHT,
    K_ESCAPE,
    KEYDOWN,
    QUIT,
)

# Initialize pygame
pygame.init()

除了模块和类之外,该pygame库还定义了许多东西。它还为击键、鼠标移动和显示属性等内容定义了一些局部常量。您可以使用语法引用这些常量pygame.<CONSTANT>。通过从 导入特定常量pygame.locals,您可以改用语法<CONSTANT>。这将为您节省一些击键并提高整体可读性。

设置显示器

现在你需要一些东西来借鉴!创建一个屏幕作为整体画布:

# Import the pygame module
import pygame

# Import pygame.locals for easier access to key coordinates
# Updated to conform to flake8 and black standards
from pygame.locals import (
    K_UP,
    K_DOWN,
    K_LEFT,
    K_RIGHT,
    K_ESCAPE,
    KEYDOWN,
    QUIT,
)

# Initialize pygame
pygame.init()

# Define constants for the screen width and height
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Create the screen object
# The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

pygame.display.set_mode()您可以通过调用并传递具有所需宽度和高度的元组或列表来创建要使用的屏幕。在这种情况下,窗口是 800x600,由常量SCREEN_WIDTH和SCREEN_HEIGHT第 20 行和第 21 行定义。这将返回Surface表示窗口内部尺寸的 a。这是您可以控制的窗口部分,而操作系统控制窗口边框和标题栏。

如果你现在运行这个程序,那么你会看到一个窗口短暂地弹出,然后在程序退出时立即消失。不要眨眼,否则您可能会错过!在下一节中,您将专注于主游戏循环,以确保您的程序仅在给出正确输入时才退出。

设置游戏循环

从 Pong 到 Fortnite 的每款游戏都使用游戏循环来控制游戏玩法。游戏循环做了四件非常重要的事情:

  • 处理用户输入
  • 更新所有游戏对象的状态
    -更新显示和音频输出
  • 保持游戏的速度

游戏循环的每个循环称为一个帧,每个循环你做的事情越快,你的游戏就会运行得越快。帧继续出现,直到满足退出游戏的某些条件。在您的设计中,有两个条件可以结束游戏循环:

  • 玩家与障碍物相撞。(稍后您将介绍碰撞检测。)
  • 播放器关闭窗口。

游戏循环所做的第一件事是处理用户输入以允许玩家在屏幕上移动。因此,您需要某种方式来捕获和处理各种输入。您可以使用pygame事件系统执行此操作。

处理事件

按键、鼠标移动甚至操纵杆移动都是用户可以提供输入的一些方式。所有用户输入都会生成一个事件。事件可以在任何时间发生,并且经常(但不总是)起源于程序之外。所有事件pygame都放在事件队列中,然后可以访问和操作。处理事件称为处理它们,执行此操作的代码称为事件处理程序。

中的每个事件pygame都有一个与之关联的事件类型。对于您的游戏,您将关注的事件类型是按键和窗口关闭。按键事件有事件类型KEYDOWN,关闭窗口事件有类型QUIT。不同的事件类型也可能具有与之关联的其他数据。例如,KEYDOWN事件类型还有一个变量调用key来指示按下了哪个键。

您可以通过调用访问队列中所有活动事件的列表pygame.event.get()。然后您遍历此列表,检查每个事件类型,并做出相应的响应:

# Variable to keep the main loop running
running = True

# Main loop
while running:
    # Look at every event in the queue
    for event in pygame.event.get():
        # Did the user hit a key?
        if event.type == KEYDOWN:
            # Was it the Escape key? If so, stop the loop.
            if event.key == K_ESCAPE:
                running = False

        # Did the user click the window close button? If so, stop the loop.
        elif event.type == QUIT:
            running = False

让我们仔细看看这个游戏循环:

  • 第 28行为游戏循环设置了一个控制变量。要退出循环和游戏,请设置running = False. 游戏循环从第 29 行开始。

  • 第 31 行启动事件处理程序,遍历事件队列中当前的每个事件。如果没有事件,则列表为空,处理程序不会做任何事情。

  • 第 35 到 38 行检查当前event.type是否是KEYDOWN事件。如果是,则程序通过查看event.key属性来检查按下了哪个键。如果键是Esc键,用 表示K_ESCAPE,则通过设置 退出游戏循环running = False。

  • 第 41 行和第 42行对名为 的事件类型进行了类似的检查QUIT。此事件仅在用户单击窗口关闭按钮时发生。用户还可以使用任何其他操作系统动作来关闭窗口。

当您将这些行添加到前面的代码并运行它时,您会看到一个带有空白或黑屏的窗口:


在您按下该键之前,该窗口不会消失Esc,或者QUIT通过关闭窗口来触发事件。

在屏幕上绘图

在示例程序中,您使用两个命令在屏幕上绘图:

1、screen.fill()填充背景

2、pygame.draw.circle()画一个圆

现在您将了解第三种绘制屏幕的方法:使用Surface。

回想一下,aSurface是一个可以在其上绘图的矩形对象,就像一张白纸。screen对象是Surface,您可以创建自己的Surface与显示屏幕分开的对象。让我们看看它是如何工作的:

# Fill the screen with white
screen.fill((255, 255, 255))

# Create a surface and pass in a tuple containing its length and width
surf = pygame.Surface((50, 50))

# Give the surface a color to separate it from the background
surf.fill((0, 0, 0))
rect = surf.get_rect()

在第 45 行用白色填充屏幕后,

Surface在第 48 行创建一个新的。这Surface是 50 像素宽,50 像素高,并分配给surf. 此时,您将其视为screen. 所以在网上,
51 你用黑色填充它。您还可以Rect使用.get_rect(). 这被存储以rect备后用。

使用.blit()和.flip()

仅仅创建一个新Surface的不足以在屏幕上看到它。为此,您需要将blit复制到Surface另一个Surface. 该术语blit代表Block Transfer,.blit()是您将一个内容复制Surface到另一个的方式。

你只能.blit()从一个Surface到另一个,但由于屏幕只是另一个Surface,这不是问题。以下是您surf在屏幕上绘制的方式:

#这一行写着“在屏幕中央绘制冲浪”
screen.blit(surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
pygame.display.flip()

第.blit()55 行的调用有两个参数:

Surface绘制_

在源上绘制它的位置Surface

坐标(SCREEN_WIDTH/2, SCREEN_HEIGHT/2)告诉您的程序放置surf在屏幕的确切中心,但看起来并不完全是这样:


图像看起来偏离中心的原因是.blit()将左上角放在surf给定位置。如果您想surf居中,那么您必须做一些数学运算才能将其向上和向左移动。您可以通过surf从屏幕的宽度和高度中减去宽度和高度来做到这一点,将每个除以 2 以定位中心,然后将这些数字作为参数传递给screen.blit()

# Put the center of surf at the center of the display
surf_center = (
    (SCREEN_WIDTH-surf.get_width())/2,
    (SCREEN_HEIGHT-surf.get_height())/2
)

# Draw surf at the new coordinates
screen.blit(surf, surf_center)
pygame.display.flip()

注意在调用 topygame.display.flip()之后调用 to blit()。这将使用自上次翻转以来绘制的所有内容更新整个屏幕。如果没有调用.flip(),则不会显示任何内容。

精灵

在您的游戏设计中,玩家从左侧开始,障碍物从右侧进入。您可以用对象来表示所有障碍物,Surface以使绘制一切变得更容易,但是您怎么知道在哪里绘制它们呢?你怎么知道障碍物是否与玩家发生碰撞?当障碍物飞出屏幕时会发生什么?如果你想绘制也会移动的背景图像怎么办?如果您希望您的图像具有动画效果怎么办?您可以使用sprites处理所有这些情况以及更多情况。

在编程术语中,精灵是屏幕上某物的 2D 表示。本质上,它是一张图片。pygame提供了一个Sprite类,该类旨在保存您想要在屏幕上显示的任何游戏对象的一个​​或多个图形表示。要使用它,您需要创建一个扩展的新类Sprite。这允许您使用其内置方法。

球员

Sprite以下是您如何在当前游戏中使用对象来定义玩家。在第 18 行之后插入此代码:

# Define a Player object by extending pygame.sprite.Sprite
# The surface drawn on the screen is now an attribute of 'player'
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super(Player, self).__init__()
        self.surf = pygame.Surface((75, 25))
        self.surf.fill((255, 255, 255))
        self.rect = self.surf.get_rect()

您首先在第 22 行Player通过扩展定义pygame.sprite.Sprite。然后.init()使用.super()调用 的.init()方法Sprite。有关为什么这是必要的更多信息,您可以阅读使用 Python super() 为您的课程增压。

接下来,您定义并初始化.surf以保存要显示的图像,该图像当前是一个白框。您还可以定义和初始化.rect,稍后您将使用它来绘制玩家。要使用这个新类,您需要创建一个新对象并更改绘图代码。展开下面的代码块以查看所有内容:

# Import the pygame module
import pygame

# Import pygame.locals for easier access to key coordinates
# Updated to conform to flake8 and black standards
from pygame.locals import (
    K_UP,
    K_DOWN,
    K_LEFT,
    K_RIGHT,
    K_ESCAPE,
    KEYDOWN,
    QUIT,
)

# Define constants for the screen width and height
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Define a player object by extending pygame.sprite.Sprite
# The surface drawn on the screen is now an attribute of 'player'
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super(Player, self).__init__()
        self.surf = pygame.Surface((75, 25))
        self.surf.fill((255, 255, 255))
        self.rect = self.surf.get_rect()

# Initialize pygame
pygame.init()

# Create the screen object
# The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

# Instantiate player. Right now, this is just a rectangle.
player = Player()

# Variable to keep the main loop running
running = True

# Main loop
while running:
    # for loop through the event queue
    for event in pygame.event.get():
        # Check for KEYDOWN event
        if event.type == KEYDOWN:
            # If the Esc key is pressed, then exit the main loop
            if event.key == K_ESCAPE:
                running = False
        # Check for QUIT event. If QUIT, then set running to false.
        elif event.type == QUIT:
            running = False

    # Fill the screen with black
    screen.fill((0, 0, 0))

    # Draw the player on the screen
    screen.blit(player.surf, (SCREEN_WIDTH/2, SCREEN_HEIGHT/2))

    # Update the display
    pygame.display.flip()

运行此代码。您将在屏幕中间大致看到一个白色矩形:

如果将第 59 行更改为 ,您认为会发生什么screen.blit(player.surf, player.rect)?试试看:

# Fill the screen with black
screen.fill((0, 0, 0))

# Draw the player on the screen
screen.blit(player.surf, player.rect)

# Update the display
pygame.display.flip()

当您将 a 传递Rect给 时.blit(),它使用左上角的坐标来绘制表面。稍后您将使用它来让您的玩家移动!

用户输入

到目前为止,您已经学习了如何pygame在屏幕上设置和绘制对象。现在,真正的乐趣开始了!您将使用键盘控制播放器。

之前,您看到它pygame.event.get()返回事件队列中的事件列表,您可以在其中扫描KEYDOWN事件类型。好吧,这不是读取按键的唯一方法。pygame还提供了pygame.event.get_pressed(),它返回一个包含队列中所有当前事件的字典。KEYDOWN

在事件处理循环之后将其放入您的游戏循环中。这将返回一个字典,其中包含在每一帧开始时按下的键:

# Get the set of keys pressed and check for user input
pressed_keys = pygame.key.get_pressed()

接下来,您编写一个方法Player来接受该字典。这将根据按下的键定义精灵的行为。这可能是这样的:

# Move the sprite based on user keypresses
def update(self, pressed_keys):
    if pressed_keys[K_UP]:
        self.rect.move_ip(0, -5)
    if pressed_keys[K_DOWN]:
        self.rect.move_ip(0, 5)
    if pressed_keys[K_LEFT]:
        self.rect.move_ip(-5, 0)
    if pressed_keys[K_RIGHT]:
        self.rect.move_ip(5, 0)

K_UP, K_DOWN, K_LEFT, 和K_RIGHT对应于键盘上的箭头键。如果该键的字典条目是True,则该键已按下,并且您将播放器移动.rect到正确的方向。在这里,您使用.move_ip()代表move in place来移动当前Rect。

然后你可以调用.update()每一帧来移动玩家精灵以响应按键。在调用后立即添加此调用.get_pressed():

# Main loop
while running:
    # for loop through the event queue
    for event in pygame.event.get():
        # Check for KEYDOWN event
        if event.type == KEYDOWN:
            # If the Esc key is pressed, then exit the main loop
            if event.key == K_ESCAPE:
                running = False
        # Check for QUIT event. If QUIT, then set running to false.
        elif event.type == QUIT:
            running = False

    # Get all the keys currently pressed
    pressed_keys = pygame.key.get_pressed()

    # Update the player sprite based on user keypresses
    player.update(pressed_keys)

    # Fill the screen with black
    screen.fill((0, 0, 0))

现在您可以使用箭头键在屏幕上移动您的播放器矩形:

你可能会注意到两个小问题:

1、如果按住某个键,播放器矩形可以非常快速地移动。你稍后会处理它。

2、播放器矩形可以移出屏幕。让我们现在解决那个问题。

要将播放器保持在屏幕上,您需要添加一些逻辑来检测是否rect要移出屏幕。为此,您检查rect坐标是否已超出屏幕边界。如果是这样,那么您指示程序将其移回边缘:

# Move the sprite based on user keypresses
def update(self, pressed_keys):
    if pressed_keys[K_UP]:
        self.rect.move_ip(0, -5)
    if pressed_keys[K_DOWN]:
        self.rect.move_ip(0, 5)
    if pressed_keys[K_LEFT]:
        self.rect.move_ip(-5, 0)
    if pressed_keys[K_RIGHT]:
        self.rect.move_ip(5, 0)

    # Keep player on the screen
    if self.rect.left < 0:
        self.rect.left = 0
    if self.rect.right > SCREEN_WIDTH:
        self.rect.right = SCREEN_WIDTH
    if self.rect.top <= 0:
        self.rect.top = 0
    if self.rect.bottom >= SCREEN_HEIGHT:
        self.rect.bottom = SCREEN_HEIGHT

在这里,您无需使用,而是直接更改、、或.move()的对应坐标。测试一下,你会发现播放器矩形不能再移出屏幕。.top.bottom.left.right

现在让我们添加一些敌人!

以上是关于PyGame:Python 游戏编程入门-1的主要内容,如果未能解决你的问题,请参考以下文章

PyGame:Python 游戏编程入门-1

Pygame - Python游戏编程入门

Pygame (Python编程从入门到实践)

用Python和Pygame写游戏-从入门到精通

用python2.7编的小游戏

pygame入门之环境配置