一、需求描述
存在四个对象:我方飞机,敌方飞机,我方子弹,敌方子弹
存在功能:我方飞机可以移动【根据按键控制】,敌方飞机随机移动,双方飞机都可以发射子弹,背景音乐添加,这个项目主要是复习之前学习的内容,其代码效果并不是特别好,
步骤:创建一个窗口
创建一个我方飞机,根据方向键移动
给我方飞机添加发射子弹功能,【空格键发射】
创建一个敌方飞机
敌人飞机可以随机移动
敌方飞机自动发射子弹
二、搭建界面和键盘检测
1.pygame介绍
Pygame是一个利用SDL库的写的游戏库,SDL呢,全名Simple DirectMedia Layer,是一位叫做Sam Lantinga的大牛写的
SDL是用C写的,不过它也可以使用C++进行开发,当然还有很多其它的语言,Pygame就是Python中使用它的一个库
2.pygame安装
安装命令:pip install pygame
提示:如果有多个版本,同时装有python 2.7 和 python3.6时可以使用
pip3 install pygame
查看已安装的第三方库:pip list 或 pip3 list
或者大家可以直接去pycharm进行安装
3.pygame 使用
Pygame有很多的模块,下面是一张一览表:
具体教程可参考官网:https://www.pygame.org/docs/
可以采用国内镜像安装利用国内镜像源安装——升级pygame - 兰花兰 - 博客园 (cnblogs.com)
4.搭建页面
代码
import pygame#引用第三方模块
from pygame.locals import *
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
# 更新显示的内容
pygame.display.update()
pass
if __name__=='__main__':
main()
5.键盘检测
import pygame#引用第三方模块
from pygame.locals import *
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#获取键盘事件
eventList=pygame.event.get()
for event in eventList:
if event.type==QUIT:#程序退出
print('退出')
exit()
elif event.type==KEYDOWN:#是否按下按键
if event.key==K_a or event.key==K_LEFT:
print('飞机左移')
elif event.key==K_d or event.key==K_RIGHT:
print('飞机右移')
elif event.key==K_SPACE:
print('发射子弹')
# 更新显示的内容
pygame.display.update()
pass
if __name__=='__main__':
main()
三、添加背景音乐
玩过飞机游戏都知道,玩的过程中是有音乐的,那pygame是如何添加音乐的呢
再次运行就会听到优美的音乐了
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
完整代码
import pygame#引用第三方模块
from pygame.locals import *
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#获取键盘事件
eventList=pygame.event.get()
for event in eventList:
if event.type==QUIT:#程序退出
print('退出')
exit()
elif event.type==KEYDOWN:#是否按下按键
if event.key==K_a or event.key==K_LEFT:
print('飞机左移')
elif event.key==K_d or event.key==K_RIGHT:
print('飞机右移')
elif event.key==K_SPACE:
print('发射子弹')
# 更新显示的内容
pygame.display.update()
pass
if __name__=='__main__':
main()
再次运行就会听到优美的音乐了
四、运行优化
1.查找原因
运行程序的过程中,我们发现一个问题,就是游戏界面运行得并不是很流畅,特别是电脑配置低的同学。查看代码,我们会发现里面有检查键盘事件的一个死循环,这也是造成程序卡顿的原因
2.解决方案
知道是循环的原因,又知道循环是为了检测键盘事件,所以死循环是不可能省略的了,但是我们可以想办法,让循环次数变少,而且变少后不影响程序对键盘的检测,比如我们让程序员秒内只检测键盘5次,这样的计算量就会大幅减少,而且和一条语句就能解决问题,如:
我们在 pygame.display.update() 后面加一条语句: pygame.time.Clock().tick(5)
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
如果发现程序对键盘的操作反应有延迟,可以修改次数,比如把每秒5次改为每秒10次,我相信一般人敲击键盘的速度还做不到每秒种能敲击10次以上,这就是合理的判断
五、控制玩具飞机-面向过程
1.原理实现及步骤
2.关键代码1
完整代码
import pygame#引用第三方模块
from pygame.locals import *
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
#载入玩家的飞机图片
hero=pygame.image.load('./feiji/hero.png')
#初始化玩家位置
x,y=0,0#后续根据操作,进行修改
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#显示玩家图片
screen.blit(hero,(x,y))
#获取键盘事件
eventList=pygame.event.get()
for event in eventList:
if event.type==QUIT:#程序退出
print('退出')
exit()
elif event.type==KEYDOWN:#是否按下按键
if event.key==K_a or event.key==K_LEFT:
if x-10>0:
x-=10 #移动五个像素
pass
print('飞机左移')
elif event.key==K_d or event.key==K_RIGHT:
if x+10<350:
x+=10
print('飞机右移')
elif event.key==K_SPACE:
print('发射子弹')
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
pass
if __name__=='__main__':
main()
六、控制玩具飞机-面向对象
实现步骤原理跟面向过程是一样的,不同的时,代码的组织方式不一样:
1、创建一个飞机类,实现左移、右移、显示三个功能
2、创建一个键盘控制函数,实现键盘的左、右、空格键的功能
3、创建主函数,实现创建窗口、背景图片、背景音乐、并实现所有的逻辑
- 创建飞机类
2.创建键盘控制函数
3.创建主函数
4.完整代码
import pygame#引用第三方模块
from pygame.locals import *
'''
1.实现飞机的显示,并且可以控制飞机的移动【面向对象】
'''
class HeroPlane(object):
def __init__(self,screen):
'''
:param screen: 主窗体对象
'''
self.x=150
self.y=450
#设置要显示内容的窗口
self.screen=screen
#生成飞机的图片对象
self.image=pygame.image.load('./feiji/hero.png')
pass
def move_left(self):
'''
飞机左移
:return:
'''
if self.x>0:
self.x-=10
pass
def move_right(self):
'''
飞机右移
:return:
'''
if self.x<350-40:#因为图片占据40个像素
self.x+=10
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
pass
def key_control(HeroObj):
'''
定义普通函数,用来实现键盘检测
:param HeroObj: 可控制的对象
:return:
'''
# 获取键盘事件
eventList = pygame.event.get()
for event in eventList:
if event.type == QUIT: # 程序退出
print('退出')
exit()
elif event.type == KEYDOWN: # 是否按下按键
if event.key == K_a or event.key == K_LEFT:
HeroObj.move_left()#调用函数实现左移动
print('飞机左移')
elif event.key == K_d or event.key == K_RIGHT:
HeroObj.move_right()
print('飞机右移')
elif event.key == K_SPACE:
print('发射子弹')
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
#载入玩家对象
hero=HeroPlane(screen)
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#显示玩家图片
hero.display()
#获取键盘事件
key_control(hero)
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
pass
if __name__=='__main__':
main()
七、玩家飞机发射子弹
1.实现原理
2.更新飞机类
3.创建子弹类
4.更新键盘控制方法
5.主函数
6.完整代码
import pygame#引用第三方模块
from pygame.locals import *
'''
1.实现飞机的显示,并且可以控制飞机的移动【面向对象】
'''
class HeroPlane(object):
def __init__(self,screen):
'''
:param screen: 主窗体对象
'''
self.x=150
self.y=450
#设置要显示内容的窗口
self.screen=screen
#生成飞机的图片对象
self.image=pygame.image.load('./feiji/hero.png')
#存放子弹列表
self.bullet_list=[]
pass
def move_left(self):
'''
飞机左移
:return:
'''
if self.x>0:
self.x-=10
pass
def move_right(self):
'''
飞机右移
:return:
'''
if self.x<350-40:#因为图片占据40个像素
self.x+=10
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
#完善子弹的展示逻辑
needDel=[]
for item in self.bullet_list:
if item.judge():
needDel.append(item)
pass
#删除越界子弹
for i in needDel:
self.bullet_list.remove(i)
pass
for bullet in self.bullet_list:
bullet.display()#显示子弹位置
bullet.move()
pass
#发射子弹
def shoot_bullet(self):
#创建一个新的子弹对象
new_bullet=Bullet(self.x,self.y,self.screen)
self.bullet_list.append(new_bullet)
pass
'''
创建子弹类
'''
class Bullet(object):
def __init__(self,x,y,screen):
'''
:param x:
:param y:
:param screen:
'''
self.x=x+13
self.y=y-20
self.screen=screen
self.image=pygame.image.load('./feiji/bullet.png')
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
pass
def move(self):
self.y-=10
pass
pass
def judge(self):
'''
判断子弹是否越界
:return:
'''
if self.y<0:
return True
else:
return False
def key_control(HeroObj):
'''
定义普通函数,用来实现键盘检测
:param HeroObj: 可控制的对象
:return:
'''
# 获取键盘事件
eventList = pygame.event.get()
for event in eventList:
if event.type == QUIT: # 程序退出
print('退出')
exit()
elif event.type == KEYDOWN: # 是否按下按键
if event.key == K_a or event.key == K_LEFT:
HeroObj.move_left()#调用函数实现左移动
print('飞机左移')
elif event.key == K_d or event.key == K_RIGHT:
HeroObj.move_right()
print('飞机右移')
elif event.key == K_SPACE:
HeroObj.shoot_bullet()
print('发射子弹')
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
#载入玩家对象
hero=HeroPlane(screen)
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#显示玩家图片
hero.display()
#获取键盘事件
key_control(hero)
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
pass
if __name__=='__main__':
main()
八、显示敌机
1.添加敌机类
2.修改主函数
九、敌机发射子弹
1.修改敌机类
2.创建敌机子弹类
3.修改主函数
4.完整代码【已经是最终效果了】
import pygame#引用第三方模块
import random#随机产生数据
import time
from pygame.locals import *
'''
1.实现飞机的显示,并且可以控制飞机的移动【面向对象】
'''
class HeroPlane(object):
def __init__(self,screen):
'''
:param screen: 主窗体对象
'''
self.x=150
self.y=450
#设置要显示内容的窗口
self.screen=screen
#生成飞机的图片对象
self.image=pygame.image.load('./feiji/hero.png')
#存放子弹列表
self.bullet_list=[]
pass
def move_left(self):
'''
飞机左移
:return:
'''
if self.x>0:
self.x-=10
pass
def move_right(self):
'''
飞机右移
:return:
'''
if self.x<350-40:#因为图片占据40个像素
self.x+=10
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
#完善子弹的展示逻辑
needDel=[]
for item in self.bullet_list:
if item.judge():
needDel.append(item)
pass
#删除越界子弹
for i in needDel:
self.bullet_list.remove(i)
pass
for bullet in self.bullet_list:
bullet.display()#显示子弹位置
bullet.move()
pass
#发射子弹
def shoot_bullet(self):
#创建一个新的子弹对象
new_bullet=Bullet(self.x,self.y,self.screen)
self.bullet_list.append(new_bullet)
pass
'''
创建子弹类
'''
class Bullet(object):
def __init__(self,x,y,screen):
'''
:param x:
:param y:
:param screen:
'''
self.x=x+13
self.y=y-20
self.screen=screen
self.image=pygame.image.load('./feiji/bullet.png')
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
pass
def move(self):
self.y-=10
pass
pass
def judge(self):
'''
判断子弹是否越界
:return:
'''
if self.y<0:
return True
else:
return False
'''
创建敌机类
'''
class EnemyPlane(object):
def __init__(self,screen):
self.screen=screen
self.x = 0
self.y = 0
# 设置要显示内容的窗口
self.screen = screen
# 生成敌机的图片对象
self.image = pygame.image.load('./feiji/enemy0.png')
# 存放子弹列表
self.bullet_list = []
#默认设置一个方向
self.direction='right'
def display(self):
self.screen.blit(self.image,(self.x,self.y))
# 完善子弹的展示逻辑
needDel = []
for item in self.bullet_list:
if item.judge():
needDel.append(item)
pass
# 删除越界子弹
for i in needDel:
self.bullet_list.remove(i)
pass
for bullet in self.bullet_list:
bullet.display() # 显示子弹位置
bullet.move()
pass
def shebullet(self):
'''
敌机随机发射子弹
:return:
'''
num=random.randint(1,8)
if num==3:
newBullet=EnemyBullet(self.x,self.y,self.screen)
self.bullet_list.append(newBullet)
def move(self):
'''
随机移动
:return:
'''
if self.direction=='right':
self.x+=10
elif self.direction=='left':
self.x-=10
if self.x>=350-20:
self.direction='left'
elif self.x<0:
self.direction='right'
'''
敌机子弹类
'''
class EnemyBullet(object):
def __init__(self,x,y,screen):
'''
:param x:
:param y:
:param screen:
'''
self.x=x
self.y=y+20
self.screen=screen
self.image=pygame.image.load('./feiji/bullet1.png')
pass
def display(self):
self.screen.blit(self.image,(self.x,self.y))
pass
def move(self):
self.y+=10
pass
pass
def judge(self):
'''
判断子弹是否越界
:return:
'''
if self.y>500:
return True
else:
return False
def key_control(HeroObj):
'''
定义普通函数,用来实现键盘检测
:param HeroObj: 可控制的对象
:return:
'''
# 获取键盘事件
eventList = pygame.event.get()
for event in eventList:
if event.type == QUIT: # 程序退出
print('退出')
exit()
elif event.type == KEYDOWN: # 是否按下按键
if event.key == K_a or event.key == K_LEFT:
HeroObj.move_left()#调用函数实现左移动
print('飞机左移')
elif event.key == K_d or event.key == K_RIGHT:
HeroObj.move_right()
print('飞机右移')
elif event.key == K_SPACE:
HeroObj.shoot_bullet()
print('发射子弹')
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
#载入玩家对象
hero=HeroPlane(screen)
#创建敌机对象
enemyplane=EnemyPlane(screen)
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#显示玩家图片
hero.display()
#显示敌机
enemyplane.display()
#敌机移动
enemyplane.move()
#敌机发射
enemyplane.shebullet()
#获取键盘事件
key_control(hero)
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
pass
if __name__=='__main__':
main()
十、优化【抽象基类】
1.优化原因
从前面的代码中,我们发现一个问题,那就是控制飞机和敌机有一部代码无论是逻辑还是功能都是一样的,那就是都有飞机移动、发谢子弹、显示子弹,这此功能;那么是不是可以把这部代码抽象出来呢,答案是肯定的, 如代码结构对比
2.添加 Plane 基类
3.修改控制机飞机类
4.修改子弹类
5.修改敌机飞机类
6.优化完整代码
import pygame#引用第三方模块
import random#随机产生数据
import time
from pygame.locals import *
'''
抽象出来一个飞机的基类
'''
class BasePlane(object):
def __init__(self,screen,imageName):
'''
:param screen: 主窗体对象
:param imageName: 加载的图片
'''
self.screen=screen
self.image=pygame.image.load(imageName)
self.bullet_list=[]#存储的子弹
pass
def display(self):
self.screen.blit(self.image, (self.x, self.y))
# 完善子弹的展示逻辑
needDel = []
for item in self.bullet_list:
if item.judge():
needDel.append(item)
pass
# 删除越界子弹
for i in needDel:
self.bullet_list.remove(i)
pass
for bullet in self.bullet_list:
bullet.display() # 显示子弹位置
bullet.move()
pass
'''
抽象出一个子弹基类
'''
class ComBullet(object):
def __init__(self,x,y,screen,bulletType):
self.x=x
self.y=y
self.type=bulletType
self.screen=screen
if self.type=='hero':
self.x+=13
self.y-=20
self.imagePath='./feiji/bullet.png'
elif self.type=='enemy':
self.x=x
self.y+=10
self.imagePath='./feiji/bullet1.png'
self.imageName=pygame.image.load(self.imagePath)
def move(self):
'''
子弹移动
:return:
'''
if self.type=='hero':
self.y-=5
elif self.type=='enemy':
self.y+=5
def display(self):
self.screen.blit(self.imageName,(self.x,self.y))
def judge(self):
'''
判断子弹是否越界
:return:
'''
if self.y>500 or self.y<0:
return True
else:
return False
'''
1.实现飞机的显示,并且可以控制飞机的移动【面向对象】
'''
class HeroPlane(BasePlane):
def __init__(self,screen):
'''
:param screen: 主窗体对象
'''
super(HeroPlane, self).__init__(screen,'./feiji/hero.png')#调用父类构造方法
self.x=150
self.y=450
pass
def move_left(self):
'''
飞机左移
:return:
'''
if self.x>0:
self.x-=10
pass
def move_right(self):
'''
飞机右移
:return:
'''
if self.x<350-40:#因为图片占据40个像素
self.x+=10
pass
#发射子弹
def shoot_bullet(self):
#创建一个新的子弹对象
new_bullet=ComBullet(self.x,self.y,self.screen,'hero')
self.bullet_list.append(new_bullet)
pass
'''
创建敌机类
'''
class EnemyPlane(BasePlane):
def __init__(self,screen):
super(EnemyPlane, self).__init__(screen,'./feiji/enemy0.png')
self.x = 0
self.y = 0
self.direction='right'
def shebullet(self):
'''
敌机随机发射子弹
:return:
'''
num=random.randint(1,8)
if num==3:
newBullet=ComBullet(self.x,self.y,self.screen,'enemy')
self.bullet_list.append(newBullet)
def move(self):
'''
随机移动
:return:
'''
if self.direction=='right':
self.x+=10
elif self.direction=='left':
self.x-=10
if self.x>=350-20:
self.direction='left'
elif self.x<0:
self.direction='right'
def key_control(HeroObj):
'''
定义普通函数,用来实现键盘检测
:param HeroObj: 可控制的对象
:return:
'''
# 获取键盘事件
eventList = pygame.event.get()
for event in eventList:
if event.type == QUIT: # 程序退出
print('退出')
exit()
elif event.type == KEYDOWN: # 是否按下按键
if event.key == K_a or event.key == K_LEFT:
HeroObj.move_left()#调用函数实现左移动
print('飞机左移')
elif event.key == K_d or event.key == K_RIGHT:
HeroObj.move_right()
print('飞机右移')
elif event.key == K_SPACE:
HeroObj.shoot_bullet()
print('发射子弹')
def main():
#首先创建一个窗口,用来显示内容
screen=pygame.display.set_mode((350,500),depth=32)#设定窗口大小
#设定背景图片
background=pygame.image.load('./feiji/background.png')#加载本地图片
#设置游戏标题
pygame.display.set_caption('阶段总结,飞机大战')
#添加背景音乐
pygame.mixer.init()
pygame.mixer.music.load('./feiji/background.mp3')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play(-1)#设置音乐播放次数,-1代表无线循环
#载入玩家对象
hero=HeroPlane(screen)
#创建敌机对象
enemyplane=EnemyPlane(screen)
while(True):
# 设定要显示的内容
screen.blit(background, (0, 0))
#显示玩家图片
hero.display()
#显示敌机
enemyplane.display()
#敌机移动
enemyplane.move()
#敌机发射
enemyplane.shebullet()
#获取键盘事件
key_control(hero)
# 更新显示的内容
pygame.display.update()
pygame.time.Clock().tick(5)#一秒内循环5次
pass
if __name__=='__main__':
main()
十一、素材链接
链接:https://pan.baidu.com/s/1Mcr95uINd9LMgoOLMslbOg?pwd=s6qi
提取码:s6qi
--来自百度网盘超级会员V4的分享