pygame

pygame

pygame简介

	Pygame 是一组用来开发游戏软件的 Python 程序模块,基于 SDL 库的基础上开发。允许你在 Python 程序中创建功能丰富的游戏和多媒体程序,Pygame 是一个高可移植性的模块可以支持多个操作系统。

    SDL,全名Simple DirectMedia Layer,是一位叫做Sam Lantinga的大牛用C写的,不过它也可以使用C++进行开发,当然还有很多其它的语言,Pygame就是Python中使用它的一个库。Pygame已经存在很多时间了,许多优秀的程序员加入其中,把Pygame做得越来越好。

pygam模块

模块名 功能
pygame.cdrom 访问光驱
pygam.cursors 加载光标
pygame.display 访问显示设备
pygame.draw 绘制形状、线、点
pygame.event 管理事件
pygame.font 使用字体
pygame.image 加载和存储图片
pygame.joystick 使用游戏手柄或者类似的东西
pygame.key 读取键盘按键
pygame.mixter 声音
pygame.mouse 鼠标
pygame.movie 播放视频
pygame.music 播放音频
pygame.overlay 访问高级视频叠加
pygame.rect 管理矩形区域
pygame.sndarray 操作声音数据
pygame.sprite 操作移动图像
pygame.surface 管理图像和屏幕
pygame.time 管理时间和帧信息
pygame.transform 缩放和移动图像

有些模块可能在某些平台不存在,可以用None来测试

 if pygam.font is None:
        print("该模块不存在!")
        exit()

pygame入门案例

参考博客:点击这里

新建一个窗口

import pygame
import sys
pygame.init() #初始化pygame
size = width, height = 800,600 #设置窗口大小
screen = pygame.display.set_mode(size) #显示窗口
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

运行结果

制作一个跳跃的小球游戏

创建一个游戏窗口,然后在窗口内创建一个小球。以一定的速度移动小球,当小球碰到游戏窗口的边缘时,小球弹回,继续运动按照如下步骤实现该功能:

创建游戏窗口

1. 创建一个游戏窗口,宽和高设置为640*480。代码如下:

import sys
import pygame
pygame.init()                       # 初始化pygame
size = width, height = 640, 480     # 设置窗口大小
screen = pygame.display.set_mode()  # 显示窗口

上述代码中,首先导入pygame模块,然后调用init()方法初始化pygame模块,接下来,设置窗口的宽和高,最后使用display模块显示窗体。

display模块的常用方法

方法名 功能
pygame.display.init() 初始化display模块
pygame.display.quit() 结束display模块
pygame.display.get_init() 如果display模块已经被初始化,则返回True
pygame.display.set_mode() 初始化一个准备显示的界面
pygame.display.get_surface() 获取当前的Surface对象
pygame.display.flip() 更新整个待显示的Surface对象到屏幕上
pygame.display.update() 更新部分内容显示到屏幕上,如果没有参数,则与flip功能相同(上一条)

保持窗口显示

2. 运行第一步的代码后会出现一个一闪而过的黑色窗口,这是因为程序执行完成后,会自动关闭。如果想要让窗口一直显示,需要使用while True让程序一直执行,此外,还需要设置关闭按钮。具体代码如下:

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 320, 240  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口

while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

pygame.quit()  # 退出pygame

上述代码中添加了轮询事件检测。pygame.event.get()能够获取事件队列,使用for...in遍历事件,然后根据type属性判断事件类型。这里的事件处理方式与GUI类似,如event.type等于pygame.QUIT表示检测到关闭pygame窗口事件,pygame.KEYDOWN表示键盘按下事件,pygame.MOUSEBUTTONDOWN表示鼠标按下事件等。

加载游戏图片

开发过程中使用的图片

3. 在窗口添加小球。我们先准备好一张ball.png
图片,然后加载该图片,最后将图片显示在窗口中,具体代码如下:

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 640, 480  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
color = (0, 0, 0)  # 设置颜色
ball = pygame.image.load('ball.png')  # 加载图片
ballrect = ball.get_rect()  # 获取矩形区域

while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()
    screen.fill(color)  # 填充颜色(设置为0,执不执行这行代码都一样)
    screen.blit(ball, ballrect)  # 将图片画到窗口上
    pygame.display.flip()  # 更新全部显示

pygame.quit()  # 退出pygame

上述代码中使用iamge模块的load()方法加载图片,返回值ball是一个Surface对象。Surface是用来代表图片的pygame对象,可以对一个Surface对象进行涂画、变形、复制等各种操作。事实上,屏幕也只是一个Surfacepygame.display.set_mode()就返回了一个屏幕Surface对象。如果将ball这个Surface对象画到screen Surface 对象,需要使用blit()方法,最后使用display模块的flip()方法更新整个待显示的Surface对象到屏幕上。

Surface对象的常用方法

方法名 功能
pygame.Surface.blit() 将一个图像画到另一个图像上
pygame.Surface.convert() 转换图像的像素格式
pygame.Surface.convert_alpha() 转化图像的像素格式,包含alpha通道的转换
pygame.Surface.fill() 使用颜色填充Surface
pygame.Surface.get_rect() 获取Surface的矩形区域

移动图片

4. 下面让小球动起来,ball.get_rect()方法返回值ballrect是一个Rect对象,该对象有一个move()方法可以用于移动矩形。move(x, y)函数有两个参数,第一个参数是 X 轴移动的距离,第二个参数是 Y 轴移动的距离。窗口的左上角是(0, 0),如果是move(100, 50)就是左移100下移50。

为实现小球不停移动,将move()函数添加到while循环内,具体代码如下:

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 640, 480  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
color = (0, 0, 0)  # 设置颜色
ball = pygame.image.load('ball.png')  # 加载图片
ballrect = ball.get_rect()  # 获取矩形区域

speed = [5, 5]  # 设置移动的X轴、Y轴
while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()
    ballrect = ballrect.move(speed)  # 移动小球
    screen.fill(color)  # 填充颜色(设置为0,执不执行这行代码都一样)
    screen.blit(ball, ballrect)  # 将图片画到窗口上
    pygame.display.flip()  # 更新全部显示

pygame.quit()  # 退出pygame

碰撞检测

5. 运行上述代码,发现小球在屏幕中一闪而过,此时,小球并没有真正消失,而是移动到窗体之外,此时需要添加碰撞检测的功能。当小球与窗体任一边缘发生碰撞,则更改小球的移动方向,具体代码如下:

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 640, 480  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
color = (0, 0, 0)  # 设置颜色
ball = pygame.image.load('ball.png')  # 加载图片
ballrect = ball.get_rect()  # 获取矩形区域
speed = [5, 5]  # 设置移动的X轴、Y轴

while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()
            
    ballrect = ballrect.move(speed)  # 移动小球
    # 碰到左右边缘
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # 碰到上下边缘
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.fill(color)  # 填充颜色(设置为0,执不执行这行代码都一样)
    screen.blit(ball, ballrect)  # 将图片画到窗口上
    pygame.display.flip()  # 更新全部显示

pygame.quit()  # 退出pygame

上述代码中,添加了碰撞检测功能。如果碰到左右边缘,更改X轴数据为负数,如果碰到上下边缘,更改Y轴数据为负数。

限制移动速度

6. 运行上述代码看似有很多球,这是因为运行上述代码的时间非常短,运行快的错觉,使用pygame的time模块,使用pygame时钟之前,必须先创建Clock对象的一个实例,然后在while循环中设置多长时间运行一次。

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 640, 480  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
color = (0, 0, 0)  # 设置颜色
ball = pygame.image.load('ball.png')  # 加载图片
ballrect = ball.get_rect()  # 获取矩形区域
speed = [5, 5]  # 设置移动的X轴、Y轴
clock = pygame.time.Clock()  # 设置时钟

while True:  # 死循环确保窗口一直显示
    clock.tick(60)  # 每秒执行60次
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    ballrect = ballrect.move(speed)  # 移动小球
    # 碰到左右边缘
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # 碰到上下边缘
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.fill(color)  # 填充颜色(设置为0,执不执行这行代码都一样)
    screen.blit(ball, ballrect)  # 将图片画到窗口上
    pygame.display.flip()  # 更新全部显示

pygame.quit()  # 退出pygame

开发Flappy Bird游戏

Flappy Bird是一款鸟类飞行游戏,一根手指操控按下小鸟上飞。

分析
在Flappy Bird游戏中,主要有两个对象:小鸟、管道。可以创建Brid类和Pineline类来分别表示这两个对象。小鸟可以通过上下移动来躲避管道,所以在Brid类中创建一个bridUpdate()方法,实现小鸟的上下移动,为了体现小鸟向前飞行的特征,可以让管道一直向左侧移动,这样在窗口中就好像小鸟在向前飞行。所以在Pineline类中也创建一个updatePipeline()方法,实现管道的向左侧移动。此外还创建了3个函数:createMap()函数用于绘制地图;checkDead()函数用于判断小鸟的生命状态;getResult()函数用于获取最终分数。最后在主逻辑中实例化并调用相关方法,实现相应的功能。

搭建主框架

# -*- coding:utf-8 -*-
import sys  # 导入sys模块
import pygame  # 导入pygame模块
import random


class Bird(object):
    """定义一个鸟类"""
    def __init__(self):
        """定义初始化方法"""
        pass

    def birdUpdate(self):
        pass


class Pipeline(object):
    """定义一个管道类"""
    def __init__(self):
        """定义初始化方法"""

    def updatePipeline(self):
        """水平移动"""


def createMap():
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))  # 填充颜色(screen还没定义不要着急)
    screen.blit(background, (0, 0))  # 填入到背景
    pygame.display.update()  # 更新显示


if __name__ == '__main__':
    pygame.init()                           # 初始化pygame
    size = width, height = 400, 650         # 设置窗口大小
    screen = pygame.display.set_mode(size)  # 显示窗口
    clock = pygame.time.Clock()             # 设置时钟
    Pipeline = Pipeline()                   # 实例化管道类
    while True:
        clock.tick(60)                      # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:   # 如果检测到事件是关闭窗口
                sys.exit()

        background = pygame.image.load("assets/background.png")  # 加载背景图片
        createMap()
    pygame.quit()  # 退出

执行结果:
img

开发过程中使用的图片

创建小鸟类、创建管道类、计算得分、碰撞检测

import pygame
import sys
import random


class Bird(object):
    """定义一个鸟类"""

    def __init__(self):
        """定义初始化方法"""
        self.birdRect = pygame.Rect(65, 50, 50, 50)  # 鸟的矩形
        # 定义鸟的3种状态列表
        self.birdStatus = [pygame.image.load("assets/1.png"),
                           pygame.image.load("assets/2.png"),
                           pygame.image.load("assets/dead.png")]
        self.status = 0      # 默认飞行状态
        self.birdX = 120     # 鸟所在X轴坐标,即是向右飞行的速度
        self.birdY = 350     # 鸟所在Y轴坐标,即上下飞行高度
        self.jump = False    # 默认情况小鸟自动降落
        self.jumpSpeed = 10  # 跳跃高度
        self.gravity = 5     # 重力
        self.dead = False    # 默认小鸟生命状态为活着

    def birdUpdate(self):
        if self.jump:
            # 小鸟跳跃
            self.jumpSpeed -= 1           # 速度递减,上升越来越慢
            self.birdY -= self.jumpSpeed  # 鸟Y轴坐标减小,小鸟上升
        else:
            # 小鸟坠落
            self.gravity += 0.2           # 重力递增,下降越来越快
            self.birdY += self.gravity    # 鸟Y轴坐标增加,小鸟下降
        self.birdRect[1] = self.birdY     # 更改Y轴位置


class Pipeline(object):
    """定义一个管道类"""

    def __init__(self):
        """定义初始化方法"""
        self.wallx = 400  # 管道所在X轴坐标
        self.pineUp = pygame.image.load("assets/top.png")
        self.pineDown = pygame.image.load("assets/bottom.png")

    def updatePipeline(self):
        """"管道移动方法"""
        self.wallx -= 5  # 管道X轴坐标递减,即管道向左移动
        # 当管道运行到一定位置,即小鸟飞越管道,分数加1,并且重置管道
        if self.wallx < -80:
            global score
            score += 1
            self.wallx = 400


def createMap():
    """定义创建地图的方法"""
    screen.fill((255, 255, 255))     # 填充颜色
    screen.blit(background, (0, 0))  # 填入到背景

    # 显示管道
    screen.blit(Pipeline.pineUp, (Pipeline.wallx, -300))   # 上管道坐标位置
    screen.blit(Pipeline.pineDown, (Pipeline.wallx, 500))  # 下管道坐标位置
    Pipeline.updatePipeline()  # 管道移动

    # 显示小鸟
    if Bird.dead:              # 撞管道状态
        Bird.status = 2
    elif Bird.jump:            # 起飞状态
        Bird.status = 1
    screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX, Bird.birdY))              # 设置小鸟的坐标
    Bird.birdUpdate()          # 鸟移动

    # 显示分数
    screen.blit(font.render('Score:' + str(score), -1, (255, 255, 255)), (100, 50))  # 设置颜色及坐标位置
    pygame.display.update()    # 更新显示


def checkDead():
    # 上方管子的矩形位置
    upRect = pygame.Rect(Pipeline.wallx, -300,
                         Pipeline.pineUp.get_width() - 10,
                         Pipeline.pineUp.get_height())

    # 下方管子的矩形位置
    downRect = pygame.Rect(Pipeline.wallx, 500,
                           Pipeline.pineDown.get_width() - 10,
                           Pipeline.pineDown.get_height())
    # 检测小鸟与上下方管子是否碰撞
    if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
        Bird.dead = True
    # 检测小鸟是否飞出上下边界
    if not 0 < Bird.birdRect[1] < height:
        Bird.dead = True
        return True
    else:
        return False


def getResutl():
    final_text1 = "Game Over"
    final_text2 = "Your final score is:  " + str(score)
    ft1_font = pygame.font.SysFont("Arial", 70)                                      # 设置第一行文字字体
    ft1_surf = font.render(final_text1, 1, (242, 3, 36))                             # 设置第一行文字颜色
    ft2_font = pygame.font.SysFont("Arial", 50)                                      # 设置第二行文字字体
    ft2_surf = font.render(final_text2, 1, (253, 177, 6))                            # 设置第二行文字颜色
    screen.blit(ft1_surf, [screen.get_width() / 2 - ft1_surf.get_width() / 2, 100])  # 设置第一行文字显示位置
    screen.blit(ft2_surf, [screen.get_width() / 2 - ft2_surf.get_width() / 2, 200])  # 设置第二行文字显示位置
    pygame.display.flip()                                                            # 更新整个待显示的Surface对象到屏幕上


if __name__ == '__main__':
    """主程序"""
    pygame.init()                            # 初始化pygame
    pygame.font.init()                       # 初始化字体
    font = pygame.font.SysFont("Arial", 50)  # 设置字体和大小
    size = width, height = 400, 650          # 设置窗口
    screen = pygame.display.set_mode(size)   # 显示窗口
    clock = pygame.time.Clock()              # 设置时钟
    Pipeline = Pipeline()                    # 实例化管道类
    Bird = Bird()                            # 实例化鸟类
    score = 0
    while True:
        clock.tick(60)                       # 每秒执行60次
        # 轮询事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if (event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN) and not Bird.dead:
                Bird.jump = True             # 跳跃
                Bird.gravity = 5             # 重力
                Bird.jumpSpeed = 10          # 跳跃速度

        background = pygame.image.load("assets/background.png")  # 加载背景图片
        if checkDead():                      # 检测小鸟生命状态
            getResutl()                      # 如果小鸟死亡,显示游戏总分数
        else:
            createMap()                      # 创建地图
    pygame.quit()

执行结果:

img

项目代码教程、资源链接:点击这里

#导入库pygame
import random
import pygame
                  
#设置常量
#颜色
#GREEN =(84,255,159)
#BLACK = (0,0,0)
width=800
heigth=600
#自定义敌机出现事件
create_enemy=pygame.USEREVENT

#初始化
pygame.init()
pygame.mixer.init()

#创建窗口
screen = pygame.display.set_mode((width,heigth))

#设置游戏名称
pygame.display.set_caption("飞机大战")

#添加系统时钟
clock = pygame.time.Clock()
pygame.time.set_timer(create_enemy,1800)
#添加背景音乐
pygame.mixer.music.load("./sound/bgLoop.wav") #音乐路径
pygame.mixer.music.set_volume(0.5)  #音量大小
pygame.mixer.music.play(-1,0)   #播放开始时间
#定义背景类
class BackGround(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image=pygame.image.load("./images/background.jpg")
        self.rect =self.image.get_rect()
        self.ready_to_move =0
    def update(self, *args):
        #背景速度与敌机速度相等时,敌机会呈静止状态,故设置self.ready_to_move调整背景移动速度
        if self.ready_to_move==0:
            self.rect.x -=1
            if self.rect.right <= 0:
                self.rect.x = self.rect.width
        if self.ready_to_move>2:
            self.ready_to_move=0
        else:
            self.ready_to_move +=1
 # 定义英雄类     
class Hero(pygame.sprite.Sprite):
    def __init__(self,speed):
        pygame.sprite.Sprite.__init__(self)
        self.image=pygame.image.load("./images/plane.png")
        self.rect =self.image.get_rect()
        self.rect.width *=0.5
        self.rect.height *=0.5
        self.image=pygame.transform.scale(self.image,(self.rect.width,self.rect.height))  #英雄图片缩放
        self.rect.y =200   #定义英雄机出现位置
        self.rect.x = 0
        self.speed=speed   #英雄移动速度
        self.ready_to_fire = 0
    #更新
    def update(self, *args, ):
        #根据键盘方向键移动,空格键发射子弹
        keys = pygame.key.get_pressed()
        if keys[pygame.K_UP]:
             self.rect.y -=self.speed
        if keys[pygame.K_DOWN]:
             self.rect.y +=self.speed
        if keys[pygame.K_LEFT]:
             self.rect.x -=self.speed
        if keys[pygame.K_RIGHT]:
             self.rect.x +=self.speed
        if keys[pygame.K_SPACE]:
            ##子弹发射需要一个缓冲时间,当self.ready_to_fire大于5后才能再次发射子弹
            if self.ready_to_fire==0:
              self.fire()
            self.ready_to_fire +=1
            if self.ready_to_fire > 5:
                self.ready_to_fire=0
        else:
            self.ready_to_fire=0

    def fire(self):
        buttle = Bullet(4)
        buttle.rect.x=self.rect.right
        buttle.rect.centery=self.rect.centery  #子弹出现位置与英雄机位置对齐
        bullet_sprit.add(buttle)
        sound = pygame.mixer.Sound("./sound/laser.wav") #子弹对象生成后,播放音效
        sound.play()
#爆炸类
class Explode(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.images= [pygame.image.load("./images/explode"+str(i)+".png") for i in range(1,4)]  #循环3张爆炸图,形成动态爆炸效果
        self.image_index=0
        self.image = self.images[self.image_index]
        self.rect = self.image.get_rect()
        self.ready_to_change =0
    def update(self,*args):
        if self.image_index < 2:
            self.ready_to_change+=1
            if self.ready_to_change %4==0:
                self.image_index +=1
                self.image = self.images[self.image_index]
        else:
            self.kill()
#初始化子弹
class Bullet(pygame.sprite.Sprite):
    def __init__(self, speed):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("./images/bullet.png")
        self.rect = self.image.get_rect()
        self.speed = speed

    def update(self, *args):
       self.rect.x +=self.speed
       if self.rect.x>width:  #当子弹飞出屏幕时,结束资源
           self.kill()

#初始化敌机
class Enemy(pygame.sprite.Sprite):
    def __init__(self,speed):
        pygame.sprite.Sprite.__init__(self)
        self.image=pygame.image.load("./images/enemy1.png")
        self.rect =self.image.get_rect()
        self.rect.y =random.randint(0,heigth)
        self.rect.x = width
        self.speed=speed
    def update(self, *args, ):
        self.rect.x -=self.speed
        if self.rect.x>width: #当敌机飞出屏幕时,结束资源
            self.kill()

#初始化英雄
hero = Hero(2)
#初始化背景
bg = BackGround()
bg2 =BackGround()
bg2.rect.x=bg2.rect.width
#初始化精灵组
hero_sprit=pygame.sprite.Group()
enemy_sprit=pygame.sprite.Group()
bullet_sprit=pygame.sprite.Group()
explode_sprit = pygame.sprite.Group()
hero_sprit.add(hero)
bg_sprit=pygame.sprite.Group()
bg_sprit.add(bg,bg2)
#游戏循环
while True:
    #刷新频率
    clock.tick(60)
    #玩家操作
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        if event.type == create_enemy:
            enemy_sprit.add(Enemy(random.randint(1,4)))
    #碰撞检测
    collision=pygame.sprite.groupcollide(enemy_sprit,bullet_sprit,True,True)
    for enemy in collision.keys():
        explode =Explode()
        explode.rect =enemy.rect
        explode_sprit.add(explode)
        sound = pygame.mixer.Sound("./sound/enemyExplode.wav")
        sound.play()

        #屏幕更新
    for group in [bg_sprit,hero_sprit,enemy_sprit,bullet_sprit,explode_sprit]:
        group.update()
        group.draw(screen)
    pygame.display.update()

posted @ 2020-12-20 22:51  废熊  阅读(1175)  评论(0)    收藏  举报