实战Python:详解利用Python和Pygame实现飞机大战

您所在的位置:网站首页 飞机大战项目经验总结 实战Python:详解利用Python和Pygame实现飞机大战

实战Python:详解利用Python和Pygame实现飞机大战

2023-03-19 23:04| 来源: 网络整理| 查看: 265

写在最前: 这篇博客很长… 如果你还不明白什么是面向对象,我建议你先不要看这个.我个人感觉飞机大战代码的难度不大,主要是让我们更加巩固面向对象的概念,促进我们对于面向对象编程的理解.PyGame已经足够方便,很多东西我们只需要定义一下就行了. 这篇博客真的很长,如果能认真看下来应该会有一些收获. 我也只是一个新手,全篇都是我手打的,图也是我自己画的,难免会有笔误,如果有错误,还望指出.谢谢. 这篇博客的代码还不够完整,后续如果有时间我希望加上声音,开始结束画面之类的 我还想开发一个类似的别的主题的游戏,哈哈哈.希望自己别被DZZH拖太久 希望看文章的你有足够耐心看完通篇,希望你有所收获.感谢.

1. 飞机大战准备 Ⅰ. 使用模块

pygame pygame是一个Python模块,转为电子游戏设计

安装pygame 我实在windows下写的代码,直接在cmd中

pip install pygame

其他系统的安装请自行百度. 如果是windows系统,安装成功后,会在python的包目录下有pygame模块,而在这个目录下,有很多例子,可以打开aliens试一下.如果可以玩,就说明安装成功了.实战Python:详解利用Python和Pygame实现飞机大战_父类

Ⅱ. 项目准备 新建飞机大战项目注意:一定要把红色框框内的选上,不然我们提前下载的包是不会被引用到项目里的.实战Python:详解利用Python和Pygame实现飞机大战_父类_02 新建一个test.py文件,并导入我们预先准备好的素材包实战Python:详解利用Python和Pygame实现飞机大战_父类_03 如何开发一个游戏? ①. 其实游戏中展现出来的运动,只不过是我们将一张张图片绘制到了游戏的窗口里并进行快速的切换. ②. 根据用户的交互情况,移动图像,产生动画效果. ③. 根据图像之间是否发生重叠,进行碰撞检测,判断是否摧毁等情况. 2. 游戏窗口 Ⅰ. 使用pygame创建图形窗口 ①. 游戏的初始化和退出

在使用pygame模块的时候,有两个方法是非常固定的.

在使用所有功能之前,需要调用init方法

在游戏结束之前,需要调用quet方法

方法 说明 pygame.init() 导入并初始化所有的pygame模块,使用其他模块之前,必须先调用init 方法 pygame.quit() 卸载所有pygame模块,在游戏结束之前调用

实战Python:详解利用Python和Pygame实现飞机大战_背景图_04 如图,这是pygame在编写代码的时候非常固定的一段:实战Python:详解利用Python和Pygame实现飞机大战_父类_05

②. 理解游戏中的坐标系 坐标系原点在左上角(0,0) x轴水平方向向右,逐渐增加 y轴垂直方向向下,逐渐增加 如图:实战Python:详解利用Python和Pygame实现飞机大战_背景图_06 在游戏中,所有可见的元素都是以矩形区域来描述位置的 要描述一个矩形区域有四个要素:(x, y) (width, height) x和y用来指定这个矩形区域左上角的坐标位置 width和height用来指定矩形区域的宽和高 在pygame中,专门提供了一个类pygame.Rect用于描述矩形区域Rect(x, y, width, height) → Rect 实战Python:详解利用Python和Pygame实现飞机大战_初始化_07 提示:当我们访问一个矩形类的size属性时候,会返回一个元组(x, y),其中x=width为矩形的宽度, y=height为矩形的高度 pygame.Rect是一个比较特殊的类,内部只是封装了一些数学计算 不执行pygame.init()方法同样可以直接使用 案例演练需求: 定义hero_rect举行描述飞机的位置和大小 输出飞机的坐标原点(x和y) 输出飞机的尺寸大小(高度和宽度)实战Python:详解利用Python和Pygame实现飞机大战_初始化方法_08 ③. 创建游戏主窗口

pygame中,专门提供了一个模块pygame.display用于创建、管理游戏窗口

法 说明 pygame.display().set_mode() 初始化窗口显示 ygame.display().update() 刷新屏幕内容显示

set.mode()方法

set_mode(resolution=(0, 0), flags=0, depth=0) -> Surface 作用 ---------- 创建游戏显示窗口 参数 ⑴resolution : 指定屏幕的 宽 和 高 ,默认创建的窗口大小和屏幕大小一直 ⑵flags : 参数指定屏幕的附加选项, 例如是否全屏等等, 默认不需要传递 ⑶depth : 参数表示颜色的位数, 默认自动匹配 返回值 暂时可以理解为游戏的屏幕, 游戏的元素都需要被绘制到游戏的屏幕上 注意 必须使用变量记录set_mode方法的返回结果! 因为后续所有的图像绘制都是基于这一个屏幕(返回结果的) PS:我们可以利用pycharm查看某张图片的像素大小.实战Python:详解利用Python和Pygame实现飞机大战_父类_09

简单的循环

为了做到游戏程序启动后,不会立即退出,通常会在游戏程序中增加一个游戏循环 所谓游戏循环就是一个无限循环 在创建游戏窗口代码下方,增加一个无限循环 注意 : 游戏窗口不需要重复创建 import pygame pygame.init() # 创建游戏的窗口 screen = pygame.display.set_mode((480, 700)) while True: pass pygame.quit() PS : 你创建完主窗口窗口关闭的时候可能会很卡,因为你现在还在无限循环里.直接用Pycharm关闭项目吧. Ⅱ. 理解 图像 并实现图像绘制 在游戏中,能够看到的游戏元素大多都是图像 图像文件起初是保存在磁盘上的,如果需要使用,第一步就需要被加载到内存 要在屏幕上看到某一个图像的内容,需要按照三个步骤: ⑴. 使用pygame.image.load()加载图像的数据 ⑵. 使用游戏屏幕(就是我们上面set_mode返回的screen)对象,调用blit方法,将图像绘制到执行的位置 ⑶. 调用pygame.display.update()方法更新整个屏幕的显示实战Python:详解利用Python和Pygame实现飞机大战_父类_10提示:如果想在屏幕上看到绘制的效果,一定要调用pygame.display.update() ①. 代码演练Ⅰ —绘制背景图像

需求:

加载background.png创建背景 将背景绘制在屏幕的(0, 0)位置 调用屏幕更新显示背景图像实战Python:详解利用Python和Pygame实现飞机大战_初始化方法_11 ②. 代码演练Ⅱ — 绘制飞机图像

需求:

加载me1.png创建飞机

将飞机绘制在屏幕的(200, 500)位置

调用屏幕更新显示背景图像牢记下面加载图像、绘制图像、更新图像的代码

# 1. 加载图像 background = pygame.image.load("./images/background.png") # 2. 绘制图像 screen.blit(background, (0, 0)) # 3. 更新图像 pygame.display.uodate()

透明图像

png格式的图像是支持透明的 在绘制图像的时候,透明区域不会显示任何内容 但是如果下方有内容,会通过透明区域显示出来

实战Python:详解利用Python和Pygame实现飞机大战_父类_12如果我们不断调整飞机的坐标,就可以让飞机不断移动.水平方向设置x,垂直方向设置y

import pygame pygame.init() # 创建游戏的窗口 screen = pygame.display.set_mode((480, 700)) # 绘制背景图像 # 1. 加载图像数据 background = pygame.image.load("./images/background.png") # 2. 调用blit绘制图像 screen.blit(background, (0, 0)) # 3. update更新屏幕显示 pygame.display.update() # 绘制飞机 plane = pygame.image.load("./images/me1.png") screen.blit(plane, (200, 500)) pygame.display.update() while True: pass pygame.quit() ③. 理解update()方法的使用

我们可以在screen对象完成所有的blit()方法后 统一调用一次display.update()方法 同样可以在屏幕上看到最终效果

使用display.set_mode()创建的screen对象是一个内存中的屏幕数据对象 可以理解为是油画的画布 screen.blit方法就是在画布上绘制许多图像 例如:飞机、敌机、子弹 这些图像可能彼此重叠或覆盖 display.update()会将画布的最终结果绘制在屏幕上,这样可以提供屏幕绘制效率,增加游戏的流畅度实战Python:详解利用Python和Pygame实现飞机大战_初始化方法_13 import pygame pygame.init() # 创建游戏的窗口 screen = pygame.display.set_mode((480, 700)) # 绘制背景图像 background = pygame.image.load("./images/background.png") screen.blit(background, (0, 0)) # pygame.display.update() # 绘制飞机 plane = pygame.image.load("./images/me1.png") screen.blit(plane, (200, 500)) # 可以在所有绘制工作完成之后, 统一调用update方法 pygame.display.update() while True: pass pygame.quit() Ⅲ. 理解 游戏循环 和 游戏时钟

我们已经将一张图片放到了屏幕上,那么如何移动呢?

①. 游戏中的动画实现原理 跟电影原理类似, 游戏中的动画效果, 本质上是快速的在屏幕上绘制图像 电影是将多张静止的电影胶片连续、快速的播放,产生连贯的视觉效果 一般在电脑上, 每秒绘制60次, 就能够达到非常连续高品质的动画效果 每次绘制的结果被称为 帧Frame ②. 游戏循环

游戏的两个组成部分

游戏循环的开始就意味着游戏的正式开始实战Python:详解利用Python和Pygame实现飞机大战_父类_14

游戏循环的作用:

保证游戏不会直接退出 变化图像位置—动画效果 每隔1/60秒移动一下所有图像的位置 调用pygame.display.update()更新屏幕显示 检测用户交互—按键、鼠标等… ③. 游戏时钟

pygame专门提供一个类pygame.time.Clock可以非常方便的设置屏幕绘制速度—刷新帧率

使用时钟对象需要两步:

在游戏初始化创建一个时钟对象 在游戏循环中让时钟调用tick(帧率)方法

tick方法会根据上次被调用的时间,自动设置游戏循环中的延时

import pygame pygame.init() # 创建游戏的窗口 screen = pygame.display.set_mode((480, 700)) # 绘制背景图像 background = pygame.image.load("./images/background.png") screen.blit(background, (0, 0)) # pygame.display.update() # 绘制飞机 plane = pygame.image.load("./images/me1.png") screen.blit(plane, (200, 500)) # 可以在所有绘制工作完成之后, 统一调用update方法 pygame.display.update() # 创建时钟对象 clock = pygame.time.Clock() i = 0 # 游戏循环 进入游戏循环内部意味着游戏正式开始 while True: clock.tick(60) print(i) i += 1 pygame.quit() ④. 飞机的简单动画实现

需求 :

在游戏初始化定义一个pygame.Rect的变量记录飞机的初始位置 在游戏循环中,每次让飞机y-1 — 向上自动移动 y = SCREEN_RECT.height: print("敌机飞出屏幕...")

⒉ 创建敌机实战Python:详解利用Python和Pygame实现飞机大战_父类_25 ⑴在__create_sprites中添加敌机精灵组 敌机是定时被创建的,因此在初始化方法中,不需要创建敌机

def __create_sprites(self): # 创建背景精灵和精灵组 background1 = BackgroundSprite() background2 = BackgroundSprite(True) self.back_group = pygame.sprite.Group(background1,background2) # 创建敌机精灵组 self.enemy_grout = pygame.sprite.Group()

⑵在__event_handler中创建敌机,并且添加到精灵组 调用精灵组的add方法,可以向精灵组中添加精灵

def __event_handler(self): # 事件监听 for event in pygame.event.get(): # 判断是否退出游戏 if event.type == pygame.QUIT: PlaneGame.__game_over() elif event.type == CREAT_ENEMY_EVENT: # 创建敌机精灵 enemy = EnemySprite() # 将敌机精灵添加到敌机精灵组 self.back_group.add(enemy)

⑶在__update_sprites中,让敌机精灵组调用update和draw方法

def __update_sprites(self): # 更新/绘制精灵组 self.back_group.update() self.back_group.draw(self.screen) self.enemy_grout.update() self.enemy_grout.draw(self.screen)

⒊ 随机敌机位置和速度

⑴导入模块

⒈ 在导入模块的时候,建议按照以下顺序导入 ① 官方标准模块导入 ② 第三方模块导入 ③ 应用程序模块导入

⒉ 修改plane_sprites.py,增加random的导入

import random

⑵随机位置实战Python:详解利用Python和Pygame实现飞机大战_背景图_26 使用pygame.Rect提供的bottom属性,在指定敌机初始位置的时候,会比较方便

bottom += y + height y = bottom - height

⑶代码实现

修改初始化方法,随机敌机出现速度和位置

def __init__(self): # 1. 调用父类方法,创建敌机精灵,同时指定敌机图片 super().__init__("./images/enemy1.png") # 2. 指定敌机的初始随即速度 1~3 self.speed = random.randint(1, 3) # 3. 指定敌机的初始随机位 置 + self.rect.bottom = 0 max_x = SCREEN_RECT.width - self.rect.width self.rect.x = random.randint(0, max_x)

⒋ 移出屏幕销毁敌机

敌机移出屏幕后,如果没有撞到我方飞机,敌机的任务就完成了 需要从敌机组删除,否则会造成内存资源的浪费

检测敌机被销毁

__del__内置方法会在对象被销毁之前被调用,在开发中,常用来判断对象是否被销毁

def __del__(self): print("敌机当场去世 %s" % self.rect)

代码实现实战Python:详解利用Python和Pygame实现飞机大战_父类_25

判断敌机是否飞出屏幕,如果是,调用kill()方法从所有组中删除

def update(self, *args): # 1. 调用父类方法,保持垂直方向的飞行 super().update() # 2. 判断是否飞出屏幕,如果飞出屏幕,如果是,需要从精灵组删除精灵 if self.rect.y >= SCREEN_RECT.height: # kill 方法可以将精灵从所有精灵组中移除,精灵就会被自动销毁 self.kill() 6. 玩家飞机 目标 : 1. 设计英雄和子弹类 2. 使用pygame.key.get_pressed()移动玩家飞机 3. 发射子弹 Ⅰ. 设计 我方飞机和子弹 类

飞机需求

游戏启动后,飞机出现在屏幕的水平中间位置,距离屏幕底部120像素 飞机每隔0.5秒发射一次子弹,每次连发三枚子弹 飞机默认不会移动,需要通过上下左右方向键,控制飞机移动

实战Python:详解利用Python和Pygame实现飞机大战_父类_28子弹需求

子弹从飞机的正上方发射沿直线向上方飞行 飞出屏幕后,需要从精灵组中删除实战Python:详解利用Python和Pygame实现飞机大战_初始化方法_29 ①. Plane 我方飞机 初始化方法 ⑴ 指定飞机图片 ⑵ 初始速度=0 — 默认不移动 ⑶ 定义bullets子弹精灵组保存子弹精灵 重写update()方法 ⑴ 飞机需要水平移动 ⑵ 并须需要保证不能移出屏幕 增加bullets属性,记录所有子弹精灵 增加fire方法,用于发射子弹 ②. Bullet 子弹 初始化方法 ⑴ 指定子弹图片 ⑵ 初始速度=-2 — 子弹向上飞行 重写update()方法 ⑴判断是否飞出屏幕,如果是,从精灵组删除 ③. 创建飞机

⒈ 准备飞机类

在plane_sprites新建Plane类

重写初始化方法,直接指定图片名称,并且将初始速度设置为0

设置飞机的初始位置实战Python:详解利用Python和Pygame实现飞机大战_ide_30

centerx = x + 0.5 * width

centery = y + 0.5 * height

bottom = y + height实战Python:详解利用Python和Pygame实现飞机大战_父类_28

class PlaneSprite(GameSprite): """飞机精灵""" def __init__(self, upright=0): # 1. 调用父类方法,设置image&speed super().__init__("./images/me1.png", 0) # 2. 设置飞机初始位置 self.rect.centerx = SCREEN_RECT.centerx self.rect.bottom = SCREEN_RECT.bottom - 120

⒉ 绘制飞机

在__create_sprites中添加飞机精灵和飞机精灵组 ① 后需要针对飞机做碰撞检测以及发射子弹 ② 所以飞机需要单独定义成属性

def __create_sprites(self): # 创建飞机的精灵和精灵组 self.plane = PlaneSprite() self.plane_group = pygame.sprite.Group()

在__update_sprites中,让飞机精灵组调用update和draw方法

def __update_sprites(self): self.plane_group.update() self.plane_group.draw(self.screen)

⒊ 移动飞机位置

在pygame中,针对键盘按键的捕获,有两种方式 第一种方式 判断event.type == pygame.KEYDOWN 第二种方式 ①首先使用pygame.key.get_pressed()返回按键元组 ②通过键盘常量,判断元组中某一个键是否被按下—如果被按下,对应的值为1

有何区别?

第一种方式

elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT: print("向右移动")

第二种方式

# 使用键盘提供的方法获取键盘按键 keys_pressed = pygame.key.get_pressed() # 判断元组中对应的按键索引值 if keys_pressed[pygame.K_RIGHT]: print("向右移动...")

结论 :

第一种方式 event.type 用户必须抬起按键才算一次按键方式,操作灵活性大打折扣 第二种方式 用户可以按住按键不放,可以实现持续向某一个方向移动,操作灵活性更好

1.移动飞机位置

演练步骤:

①. 在Plane类中重写update方法

用速度speed和英雄rect.x进行叠加 不需要调用父类方法—父类方法只是实现了单纯的垂直运动 def update(self, *args): # 飞机在水平方向移动 self.rect.x += self.speed self.rect.y += self.upright # 控制飞机不能离开屏幕 if self.rect.x SCREEN_RECT.right: self.rect.right = SCREEN_RECT.right elif self.rect.y 0: # 让英雄牺牲 self.plane.kill() # 结束游戏 PlaneGame.__game_over() 8. 最终效果

实战Python:详解利用Python和Pygame实现飞机大战_ide_35写在最后 这篇博客我从十一月就开始写,一直到拖到现在. 最近项目事多,自己也有点变懒 还望自己不忘初心. 一起努力,一起进步.



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3