会打飞机吗?原来用 Python 实现打飞机更爽
所用技术和软件
python 2.7
pygame 1.9.3
pyCharm
准备工作
安装好 pygame 在第一次使用 pygame 的时候,pyCharm 会自动 install pygame。
下载好使用的素材。
技术实现
初始化 pygame
首先要初始化 pygame ,之后设定一些基本的要点,比如窗口大小(尽量避免魔法数字),窗口标题以及背景图像。pygame 通过加载图片,最后返回一个 surface 对象,我们不需要关系图片的格式。但是通过 convert()
这个函数,会使我们的图片转换效率提高。
# coding=utf8import pygameWIDTH = 480HEIGHT = 800pygame.init()screen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption('飞机大战')background = pygame.image.load('resources/image/background.png').convert()screen.fill(0)screen.blit(background, (0, 0))
默认图片左上角为原点 (0,0)。
显示窗口
如果我们这样设定,当我们运行的时候,窗口会一闪而过,并不会出现我们想象的画面。因为窗口只是运行一下就会关闭,所以我们要写一个循环,使窗口一直保持出现。当然如果我们简单的写一个 while True那么我们的程序就出现了死循环,卡死。
所以还需要写个退出。
while True:screen.fill(0)screen.blit(background, (0, 0))for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()exit()
显示飞机
首先我们要初始化我们的主角飞机
仍旧需要加载我们需要的资源,我们的资源文件里已经准备好各种各样的飞机,但是他们都在一张切图上。
同时我们的资源文件里还有一个叫做 shoot.pack
的文件,里面记录了每个图片所在的位置。
我们通过下面的代码加载资源图片,并且获得我们需要的主角飞机。
plane_img = pygame.image.load('resources/image/shoot.png')player = plane_img.subsurface(pygame.Rect(0, 99, 102, 126))
将 player 显示在屏幕上,并且刷新屏幕
screen.blit(player, [100, 400])pygame.display.update()
效果如下
让飞机 “飞” 起来
飞机已经出现在我们的屏幕上了,现在需要让飞机动起来让他可以上下左右的移动。
首先要获取键盘事件,获取键盘上什么按键被按下。
key_pressed = pygame.key.get_pressed()
通过 key_pressed
获取当前的键盘按键。并进行判断,这里写了四个函数进行对 player
移动。
if key_pressed[pygame.K_w] or key_pressed[pygame.K_UP]:player.moveUp()if key_pressed[pygame.K_s] or key_pressed[pygame.K_DOWN]:player.moveDown()if key_pressed[pygame.K_a] or key_pressed[pygame.K_LEFT]:player.moveLeft()if key_pressed[pygame.K_d] or key_pressed[pygame.K_RIGHT]:player.moveRight()
下一步就是完善这四个方法。
简单的说就是按下方向键的时候(w,a,s,d)飞机向四周移动,但是不能移动离开屏幕。
此时我们就应该把我们的飞机形成一个类,类里面有控制飞机的方法。
这里写类比较麻烦一点
Player的出现
首先要明确一点,这个类需要什么。
我们之前对 player
有什么操作?定义了他的图片和他出现的位置。所以我们的构造方法就要初始化这些值。pygame
里叫做精灵(sprite),这个概念也在其他游戏开发中使用。
class Player(pygame.sprite.Sprite):def __init__(self, plane_img, player_rect, player_position):pygame.sprite.Sprite.__init__(self)self.img = plane_img.subsurface(player_rect)self.rect = player_rectself.rect.topleft = player_position
简单的说就是获取飞机的图片,初始化飞机的矩形区域。rect
该属性会获得四个值。分别是左上角 x
,y
坐标,矩形的宽度。topleft
初始化飞机的左上角坐标,也就是飞机出现的位置。如下图所示。
player的控制
当飞机出现了,我们就应该实现我们在循环里写的方法。我们首先要判断它还在不在屏幕内,不能让飞机飞出屏幕。可以通过 rect.top
,rect.bottom
,rect.left
,rect.right
四个方法获取飞机图片的上下左右四个边界值。
这样我们就能对飞机进行判断
def moveUp(self):if self.rect.top <= 0:self.rect.top = 0else:self.rect.top -= self.movedef moveDown(self):if self.rect.bottom >= HEIGHT:self.rect.bottom = HEIGHTelse:self.rect.bottom = self.movedef moveLeft(self):if self.rect.left <= 0:self.rect.left = 0else:self.rect.left -= self.movedef moveRight(self):if self.rect.right >= WIDTH:self.rect.right = WIDTHelse:self.rect.right = self.move
这里的 move
是我们对飞机的移动的位移定义的常量。
让子弹飞
子弹要沿着发射方向射出去。可以在屏幕上一直移动,直到移出屏幕。player
一样,获得图片,裁剪图片,设置图片初始位置,在屏幕上显示图片
class Bullet(pygame.sprite.Sprite):def __init__(self, bullet_image, bullet_position):pygame.sprite.Sprite.__init__(self)self.image = bullet_imageself.rect = self.image.get_rect()self.rect.midbottom = bullet_position# 省略其他代码# 加载子弹图片bullet_rect = pygame.Rect(69, 78, 9, 21)bullet_img = plane_img.subsurface(bullet_rect)# 省略其他代码while True:# 省略其他代码screen.blit(bullet.img, bullet.rect)# 省略其他代码
运行结果
下一步就是让飞机的子弹跟随飞机。
if key_pressed[pygame.K_SPACE]:player.shoot()
完善shoot方法。子弹类已经有了,我们每次只要在按下空格的时候创建一个对象就好。pygame.sprite.Group()
来存放精灵组。这样我们就能把我们的子弹都放进去。
def shoot(self, bullet_img):bullet = Bullet(bullet_img, self.rect.midtop)self.bullets.add(bullet)
每次按下空格的时候传入一个子弹图片
if key_pressed[pygame.K_SPACE]:player.shoot(bullet_img)
最后我们只需要在屏幕上进行子弹的绘制即可。
player.bullets.draw(screen)
这样我们的子弹就会跟随飞机出现。
下一步就是让子弹在屏幕上移动。
创建移动的方法。
def move(self):self.rect.top -= self.move
因为我们的子弹在 bullets 里,所以我们仅需要一个循环,遍历每个子弹,之后移动即可。当子弹移出屏幕的时候我们只要在 bullets
中移出就可以。
for bullet in player.bullets:bullet.bulletMove()if bullet.rect.bottom < 0:player.bullets.remove(bullet)
结果
这个和我们的预期还是有差别的,频率太快了。
关于pygame 的键盘重复事件 官方好像并没有这个设置。那么我们只能在添加一个计数器,通过计算器的数值来判断子弹是否发射。这里的数值是多次测试后,自己感觉一个比较满意的频率。可以自己调整。
# 省略其他代码# 子弹频率SHOOT_PC = 0
在键盘事件中我们需要判断频率。
if key_pressed[pygame.K_SPACE]:SHOOT_PC = SHOOT_PC 1if SHOOT_PC % 400 == 0:player.shoot(bullet_img)
player 的飞机就算基本绘制好了
绘制敌机
下一步就是绘制敌机。敌机是从屏幕上方移动到屏幕下方。我们任就需要一个类来设置敌机。设置类任就和我们前面的差不多,加载资源,设置 rect
,设置位置。
# 加载敌机图片enemy_rect = pygame.Rect(267, 347, 57, 51)enemy_img = plane_img.subsurface(enemy_rect)enemy_position = [200, 200]enemy = Enemy(enemy_img, enemy_position)# 敌机类class Enemy(pygame.sprite.Sprite):def __init__(self, enemy_img, enemy_position):pygame.sprite.Sprite.__init__(self)self.image = enemy_imgself.rect = self.image.get_rect()self.rect.topleft = enemy_position
最后在屏幕显示出来
1
screen.blit(enemy_img, enemy_rect)
现在我们就应该想想敌机的特点了,其实他和子弹的特点基本一直,只不过方向不一样而已。还有一点是敌机是随机生成的。
# 敌机计数器EnEMY_PC = 0# 省略代码enemy_position = [random.randint(0, WIDTH - enemy_rect.width), 0]enemy = Enemy(enemy_img, enemy_position)enemies.add(enemy)
我们随机在顶部生成飞机。
这个方式的情况和子弹其实差不多,我们应该给出现敌机确定一个频率。
if EnEMY_PC % 500 == 0:enemy_position = [random.randint(0, WIDTH - enemy_rect.width), 0]enemy = Enemy(enemy_img, enemy_position)enemies.add(enemy)EnEMY_PC = EnEMY_PC 1
这样的话出现情况就变得缓慢。下一步实现敌机的移动。敌机的移动原理和子弹的移动其实也是一样的。不多解释
移动方法
def enemyMove(self):self.rect.top = self.move
移动实现
for enemy in enemies:enemy.enemyMove()if enemy.rect.top > HEIGHT:enemies.remove(enemy)enemies.draw(screen)
碰撞检测
飞机和敌机还有子弹都有了,我们现在需要进行完成碰撞检测。有下面几种场景。
敌机和玩家碰撞在一起
子弹和敌机碰撞在一起
无论是那种情况的碰撞,其实就是两张图片有了交集。sprite
。通过 pygame.sprite.collide_rect()
进行碰撞检测。
我们先进行一个测试
if pygame.sprite.collide_rect(enemy, player):print '检测成功'
结果
检测成功
此时我们就可以完成,当玩家和敌机发生碰撞,游戏结束,当子弹和敌机碰撞,敌机消失。
同样的 pygame 给我们提供了一个 pygame.sprite.groupcollide()
用于 Group
之间的碰撞检测.当发生碰撞的时候这两个对象都会在 Group
中移出。
用于检测敌机和子弹
pygame.sprite.groupcollide(enemies, player.bullets, 1, 1)
敌机和子弹的关系已经和好的处理。
我们需要在 Player
里添加一个属性判断当前玩家是否被击中的 boolean
值.当集中的时候把属性改为 True
.当为 True
的时候游戏结束.也就是我们一开始设置的循环就会结束.所以我们需要更改之前写的一些代码,使它更加完善。
在 Player 类里面添加是否击中属性。
self.is_hit = False
修改循环
RUN = Truewhile RUN:# 省略代码if pygame.sprite.collide_rect(enemy, player):player.is_hit = TrueRUN = False# 省略代码
执行结果
当玩家被击中的时候,在显示一张 GameOver 图片提示
gameOver = pygame.image.load('resources/image/gameover.png')while GAMEOVER:screen.fill(0)screen.blit(gameOver, (0, 0))pygame.display.update()# 退出程序for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()exit()
做到这里基本算是实现了飞机大战.但是还有很多细节处理。
细节处理
精细的碰撞检测
从图上看,当敌机看似还没有和我们接触时,但是已经 GameOver 了。
我们可以按着图片中心的某个长度为半径,在这个半径内发生碰撞才是碰撞。
pygame 给我们提供了这样的方法。pygame.sprite.collide_circle_ratio()
可以自己算出一个半径,作为检测半径。并且可以做出一个有效检测的百分比。
if pygame.sprite.collide_circle_ratio(0.6)(player, enemy):player.is_hit = TrueRUN = False
同样,子弹和敌机也可以修改,让碰撞检测更加精细。
pygame.sprite.groupcollide(enemies, player.bullets, 0.6, 0.8)
动画
做了怎么就,感觉它没有一点动效,感觉死气沉沉的。无论是飞机飞行,还是飞机被击中,都没有一个明确的反馈。
首先我们更改我们的主角 Player
player_rect = [pygame.Rect(0, 99, 102, 126),pygame.Rect(165, 360, 102, 126),pygame.Rect(165, 234, 102, 126),pygame.Rect(330, 624, 102, 126), pygame.Rect(330, 498, 102, 126), pygame.Rect(432, 624, 102, 126)]player_position = [100, 400]player = Player(plane_img, player_rect, player_position)
之后在 Player
添加循环的方法。获取图片。
class Player(pygame.sprite.Sprite):def __init__(self, plane_img, player_rect, player_position):pygame.sprite.Sprite.__init__(self)self.image = []for i in range(len(player_rect)):self.image.append(plane_img.subsurface(player_rect[i]).convert_alpha())self.rect = player_rect[0]self.rect.topleft = player_positionself.img_index = 0self.move = 1self.bullets = pygame.sprite.Group()self.is_hit = False
飞机正常飞行的图片只有两张。所以我们要循环变化这两张图片。所以每发射一个子弹,图片变化两张。
screen.blit(player.image[player.img_index], player.rect)player.img_index = SHOOT_PC / 248# 省略代码if key_pressed[pygame.K_SPACE]:if SHOOT_PC % 495 == 0:player.shoot(bullet_img)SHOOT_PC = SHOOT_PC 1if SHOOT_PC >= 495:SHOOT_PC = 0
正常发射子弹的动画效果已经做完。我们还需要进行被击中爆炸的动画效果。
击中的原理和正常也一样。只不过先要判断当前飞机状态,是否被击中。
if not player.is_hit:screen.blit(player.image[player.img_index], player.rect)player.img_index = SHOOT_PC / 248else:player.img_index = player_shoot / 248screen.blit(player.image[player.img_index], player.rect)player_shoot = 30if player_shoot > 495:RUN = False# 省略代码if pygame.sprite.collide_circle_ratio(0.6)(player, enemy):player.is_hit = True
248
,30
,495
,1457
这些数字是什么?如何计算出来的。先说 495
这个数字。
1488 这个数字是通过 248 确定的,是 248 的 6倍,因为飞机被射击后会有四张图片的显示。
加载图片
enemies_shoot_img = [plane_img.subsurface(pygame.Rect(267, 347, 57, 43)),plane_img.subsurface(pygame.Rect(873, 697, 57, 43)),plane_img.subsurface(pygame.Rect(267, 296, 57, 43)),plane_img.subsurface(pygame.Rect(930, 697, 57, 43))]
同样我们需要创建 Group() 来存放被击中的敌机。
enemies_shoot = pygame.sprite.Group()
之后的处理逻辑基本相似,不多介绍
for enemy in enemies:enemy.enemyMove()if pygame.sprite.collide_circle_ratio(0.6)(player, enemy):enemies_shoot.add(enemy)enemies.remove(enemy)player.is_hit = Truebreakif enemy.rect.top > HEIGHT:enemies.remove(enemy)for enemy_shoots in enemies_shoot:if enemy_shoots.shoot_index == 0:passif enemy_shoots.shoot_index > 70:enemies_shoot.remove(enemy_shoots)continuescreen.blit(enemy_shoots.shoot_imgs[enemy_shoots.shoot_index / 20], enemy_shoots.rect)enemy_shoots.shoot_index = 1
这样的话基本完成了动画效果。
音乐
有了动画还的有音乐。
音乐的处理只要在特定的地方播放音乐就好,比如子弹发射的时候,背景音乐,被击中的时候,游戏结束的时候,等等。他们的处理逻辑都一样。先加载资源,然后在播放。
背景音乐的播放。
pygame
在处理背景音乐的时候都在 pygame.mixer
方法中。其中播放音乐的play中的参数,第一个为播放几次,-1 为循环播放,后面的浮点表示 从第几秒开始播放。
backgroundMusic = pygame.mixer.music.load('resources/sound/game_music.mp3')pygame.mixer.music.play(-1, 0.0)
其他的音乐先加载资源,在需要的地方播放。
发射子弹
def shoot(self, bullet_img):shootMusic = pygame.mixer.Sound('resources/sound/bullet.mp3')bullet = Bullet(bullet_img, self.rect.midtop)self.bullets.add(bullet)shootMusic.play()
其他音乐处理一样,不多解释。
分数&等级
分数
首先绘制得分情况,在屏幕上显示多少分。
绘制字体基本和绘制精灵是差不多的。首先要生成字体
score_font = pygame.font.Font(None, 36)
有了字体那么需要写点字。
score_font.render("分数",True,(0,0,0),(255,255,255))
第一个参数是写的文字;第二个参数是个布尔值,以为这是否开启抗锯齿,就是说True的话字体会比较平滑,不过相应的速度有一点点影响;第三个参数是字体的颜色;第四个是背景色,如果你想没有背景色(也就是透明),那么可以不加这第四个参数get_rect()
获得矩形,之后绘制和精灵绘制方法一样
score_font = pygame.font.Font(None, 36)score_text = score_font.render('分数:0', True, (128, 128, 128))text_rect = score_text.get_rect()text_rect.topleft = [10, 10]screen.blit(score_text, text_rect)
分数已经显示了,就可以积分。我们每击落一个飞机增加 100 分。
if enemy_shoots.shoot_index > 70:enemies_shoot.remove(enemy_shoots)score = 100continue
我们还需要在文本的地方强制转换为 str 。
score_text = score_font.render(str(score), True, (128, 128, 128))
等级
有了分数,那么再加点等级会使游戏更加有趣味性。
同样的先绘制等级。
level_font = pygame.font.Font(None, 42)level_text = level_font.render('Level 'str(level), True, (128, 128, 128, 128))level_rect = level_text.get_rect()level_rect.midtop = [240, 10]screen.blit(level_text, level_rect)
下一步就是写等级函数。
if score == 100 \* (level ** 2 \ level):level = 1
这个是控制敌机数量的,我们可以设定一个变量,使敌机越来越多。
if ENEMY_PC % 500 == 0:
每增加一级,就添加敌机数量。等级也不能一直增加,所以当等级是摸个值的时候,就算最高级别了。
if score == 100 \* (level ** 2 \ level):level = 1if level != 10:enemy_add -= 20
基本到这里算是写了一个相对完整的游戏。
代码
Github地址:https://github.com/youngxhui/PlaneWars
原文地址:http://youngxhui.top/2017/06/22/python-%E5%AE%9E%E7%8E%B0%E5%BE%AE%E4%BF%A1%E6%89%93%E9%A3%9E%E6%9C%BA/#hcq=Y6ZlhXq
转发此文到朋友圈并截图到后台,
获得20G
python入门视频课
往期实战及福利
关注本公众号,牧原小主 送您
2.7G 380份最新数据分析报告
40G 人工智能算法课
已关注的小伙伴,直接回复数据分析报告、人工智能算法
关注后,回复 PM2.5 获得 Python分析北京PM2.5,原来每年的值都在变少...所有源代码
关注后,回复“python3.7”,获得python 3.7官方最新pdf 文档
关注后,回复 世界杯, 获得 2018世界杯来了,利用Python预测冠军(附全部代码和数据集)所有源代码
关注后,回复“豆瓣电影“,获得 Python实战 | 手把手教你爬取豆瓣电影 Top 250(附全部代码及福利哦)所有源代码
关注后,回复“python可视化”,获得 利用python“三步”实现数据可视化,炫的不要不要的!所有源代码
会打飞机吗?原来用 Python 实现打飞机更爽相关推荐
- 用 Python 实现打飞机,让子弹飞吧!
2019独角兽企业重金招聘Python工程师标准>>> 所用技术和软件 python 2.7 pygame 1.9.3 pyCharm 准备工作 安装好 pygame 在第一次使用 ...
- 用 Python 实现打飞机
全世界只有3.14 % 的人关注了 数据与算法之美 所用技术和软件 python 2.7 pygame 1.9.3 pyCharm 准备工作 安装好 pygame 在第一次使用 pygame 的时候, ...
- python写打飞机游戏
python与打飞机(飞碟) 打飞机小游戏应该算得上是入门python最经典的游戏了,在大部分教程中都有所介绍,不过一般缺乏一定的创新性和可玩性,例如ALIEN INVASION项目的介绍中作出了就是 ...
- pygame小项目 ~ 3 :Python完成简易飞机大战
pygame小项目 ~ 3 :Python完成简易飞机大战 子弹 敌机 我方战斗机全部采用图片 子弹击中和战斗机被击中全部采用碰撞检测 游戏的主函数代码 import spite from spite ...
- 用python做飞机大战打到不同部位扣分不同_python制作飞机大战需要哪些python术语...
怎么样用Python写飞机大战游戏 为什么写出来一直都是未响应,哪里写错了吗?就算小编们没能走到最后,小编也不会心存遗憾,你有你的苦辣酸甜,小编有小编的喜怒哀乐,如果小编们不曾相遇,就没有那些美好记忆 ...
- python入门笔记——飞机大战(极简版、未进行继承优化)
python入门笔记--飞机大战(极简版.未进行继承优化) import random import pygame# 引用pygame里的模块 from pygame.locals import *# ...
- python如何实现飞机上下移动_python项目实战 打飞机(二)
叁研伴学路,良语暖人心.考研路漫漫,功在每日勤.日推价值文,资料资讯精.何不速关注,大业或可行? 有了上一节的一些介绍,大家应该对pygame不陌生了,所以后面怎么查文档就不介绍了,主要是完成这个项目 ...
- 可以帮我做一个python的3D飞机小游戏吗
当然可以!我很乐意帮助你做一个 Python 的 3D 飞机小游戏. 如果你是 Python 初学者,我建议你先了解一些 Python 的基础知识,包括变量.数据类型.流程控制语句.函数等.这些知识都 ...
- Python 飞机大战游戏中 获取被击中飞机的坐标位置信息
Python 飞机大战游戏中 获取被击中飞机的坐标位置信息 在参考现有的飞机大战游戏代码,写第一个python游戏,子弹击中飞机后,飞机消失,想着如果能有爆照效果就好了. 于是新建了一个爆炸效果的sp ...
- python飞机大战源码素材包_小甲鱼python基础教程飞机大战源码及素材
原博文 2018-12-22 23:32 − 百度了半天小甲鱼python飞机大战的源码和素材,搜出一堆不知道是什么玩意儿的玩意儿. 最终还是自己对着视频一行行代码敲出来. 需要的同学点下面的链接自取 ...
最新文章
- 如何用Python玩转比特币?(附源码)
- DroidPilot 发布微信公众帐号啦~
- java Executor实例_Executor框架+实例
- C/S和B/S两种模式
- 01_Win10下CUDA的安装、查看并升级Nvidia显卡驱动、安装CUDA、设置环境变量、测试CUDA是否安装成功
- MVC 页面传参到另一个页面
- python任务调度系统web_监听调度系统定时执行任务python_websock
- [转载] Java中自定义异常的声明与处理
- Mac 启动时屏幕上的特殊图像标识都是什么意思
- 网络爬虫与信息提取学习笔记_02
- Python爬虫案例——漫画网站爬取图片(模拟浏览器解析网页)
- 电脑主板上的一些电子元件
- Oracle账户被锁定后如何解锁
- 通过 SiteServer CMS 推进政府网站集约化、集群化建设
- 小程序报错 出现脚本错误或者未正确调用 Page()
- S4 HANA CO和FI自动集成:成本中心分配分摊业务实践-KSV5/KSU5
- 用ssm进行微信开发,实现微信登录验证功能
- 关于网线水晶头的接法详解
- Msfvenonm生成后门木马
- 日期控件My97的时间限制
热门文章
- DataLossError : corrupted record at XXXXXXX,BERT预训练报错
- 19 年 3 月 GitHub 上最流行的 34 个 JS 仓库
- Mil学习之 MimArith 图片逻辑运算
- 仿b站Java_推荐 9 个 GitHub 上练手项目(在线考试、仿美团、仿抖音、仿B站、仿头条...)...
- Redis底层数据结构-SDS
- java byte(字节)根据长度转成kb(千字节)和mb(兆字节)
- 32767+1=-32768 补码
- HyperLogLog算法及原理
- oneDrive登陆界面空白 的解决办法
- 中考计算机易错知识点,中考语文常见的易错考点23个