所用技术和软件

  • python 2.7

  • pygame 1.9.3

  • pyCharm

准备工作

  1. 安装好 pygame 在第一次使用 pygame 的时候,pyCharm 会自动 install pygame。

  2. 下载好使用的素材。

技术实现

初始化 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)

碰撞检测

飞机和敌机还有子弹都有了,我们现在需要进行完成碰撞检测。有下面几种场景。

  1. 敌机和玩家碰撞在一起

  2. 子弹和敌机碰撞在一起

无论是那种情况的碰撞,其实就是两张图片有了交集。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

248304951457 这些数字是什么?如何计算出来的。先说 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入门视频课

往期实战及福利


  1. 关注本公众号,牧原小主 送您

    1. 2.7G  380份最新数据分析报告

    2. 40G  人工智能算法课

    3. 已关注的小伙伴,直接回复数据分析报告、人工智能算法

  2. 关注后,回复 PM2.5 获得 Python分析北京PM2.5,原来每年的值都在变少...所有源代码

  3. 关注后,回复“python3.7”,获得python 3.7官方最新pdf 文档

  4. 关注后,回复 世界杯, 获得 2018世界杯来了,利用Python预测冠军(附全部代码和数据集)所有源代码

  5. 关注后,回复“豆瓣电影“,获得 Python实战 | 手把手教你爬取豆瓣电影 Top 250(附全部代码及福利哦)所有源代码

  6. 关注后,回复“python可视化”,获得 利用python“三步”实现数据可视化,炫的不要不要的!所有源代码


长按二维码,关注我们

会打飞机吗?原来用 Python 实现打飞机更爽相关推荐

  1. 用 Python 实现打飞机,让子弹飞吧!

    2019独角兽企业重金招聘Python工程师标准>>> 所用技术和软件 python 2.7 pygame 1.9.3 pyCharm 准备工作 安装好 pygame 在第一次使用 ...

  2. 用 Python 实现打飞机

    全世界只有3.14 % 的人关注了 数据与算法之美 所用技术和软件 python 2.7 pygame 1.9.3 pyCharm 准备工作 安装好 pygame 在第一次使用 pygame 的时候, ...

  3. python写打飞机游戏

    python与打飞机(飞碟) 打飞机小游戏应该算得上是入门python最经典的游戏了,在大部分教程中都有所介绍,不过一般缺乏一定的创新性和可玩性,例如ALIEN INVASION项目的介绍中作出了就是 ...

  4. pygame小项目 ~ 3 :Python完成简易飞机大战

    pygame小项目 ~ 3 :Python完成简易飞机大战 子弹 敌机 我方战斗机全部采用图片 子弹击中和战斗机被击中全部采用碰撞检测 游戏的主函数代码 import spite from spite ...

  5. 用python做飞机大战打到不同部位扣分不同_python制作飞机大战需要哪些python术语...

    怎么样用Python写飞机大战游戏 为什么写出来一直都是未响应,哪里写错了吗?就算小编们没能走到最后,小编也不会心存遗憾,你有你的苦辣酸甜,小编有小编的喜怒哀乐,如果小编们不曾相遇,就没有那些美好记忆 ...

  6. python入门笔记——飞机大战(极简版、未进行继承优化)

    python入门笔记--飞机大战(极简版.未进行继承优化) import random import pygame# 引用pygame里的模块 from pygame.locals import *# ...

  7. python如何实现飞机上下移动_python项目实战 打飞机(二)

    叁研伴学路,良语暖人心.考研路漫漫,功在每日勤.日推价值文,资料资讯精.何不速关注,大业或可行? 有了上一节的一些介绍,大家应该对pygame不陌生了,所以后面怎么查文档就不介绍了,主要是完成这个项目 ...

  8. 可以帮我做一个python的3D飞机小游戏吗

    当然可以!我很乐意帮助你做一个 Python 的 3D 飞机小游戏. 如果你是 Python 初学者,我建议你先了解一些 Python 的基础知识,包括变量.数据类型.流程控制语句.函数等.这些知识都 ...

  9. Python 飞机大战游戏中 获取被击中飞机的坐标位置信息

    Python 飞机大战游戏中 获取被击中飞机的坐标位置信息 在参考现有的飞机大战游戏代码,写第一个python游戏,子弹击中飞机后,飞机消失,想着如果能有爆照效果就好了. 于是新建了一个爆炸效果的sp ...

  10. python飞机大战源码素材包_小甲鱼python基础教程飞机大战源码及素材

    原博文 2018-12-22 23:32 − 百度了半天小甲鱼python飞机大战的源码和素材,搜出一堆不知道是什么玩意儿的玩意儿. 最终还是自己对着视频一行行代码敲出来. 需要的同学点下面的链接自取 ...

最新文章

  1. 如何用Python玩转比特币?(附源码)
  2. DroidPilot 发布微信公众帐号啦~
  3. java Executor实例_Executor框架+实例
  4. C/S和B/S两种模式
  5. 01_Win10下CUDA的安装、查看并升级Nvidia显卡驱动、安装CUDA、设置环境变量、测试CUDA是否安装成功
  6. MVC 页面传参到另一个页面
  7. python任务调度系统web_监听调度系统定时执行任务python_websock
  8. [转载] Java中自定义异常的声明与处理
  9. Mac 启动时屏幕上的特殊图像标识都是什么意思
  10. 网络爬虫与信息提取学习笔记_02
  11. Python爬虫案例——漫画网站爬取图片(模拟浏览器解析网页)
  12. 电脑主板上的一些电子元件
  13. Oracle账户被锁定后如何解锁
  14. 通过 SiteServer CMS 推进政府网站集约化、集群化建设
  15. 小程序报错 出现脚本错误或者未正确调用 Page()
  16. S4 HANA CO和FI自动集成:成本中心分配分摊业务实践-KSV5/KSU5
  17. 用ssm进行微信开发,实现微信登录验证功能
  18. 关于网线水晶头的接法详解
  19. Msfvenonm生成后门木马
  20. 日期控件My97的时间限制

热门文章

  1. DataLossError : corrupted record at XXXXXXX,BERT预训练报错
  2. 19 年 3 月 GitHub 上最流行的 34 个 JS 仓库
  3. Mil学习之 MimArith 图片逻辑运算
  4. 仿b站Java_推荐 9 个 GitHub 上练手项目(在线考试、仿美团、仿抖音、仿B站、仿头条...)...
  5. Redis底层数据结构-SDS
  6. java byte(字节)根据长度转成kb(千字节)和mb(兆字节)
  7. 32767+1=-32768 补码
  8. HyperLogLog算法及原理
  9. oneDrive登陆界面空白 的解决办法
  10. 中考计算机易错知识点,中考语文常见的易错考点23个