目录
一、课程设计目的及应用背景
二、课程设计内容
三、课程设计代码实现
1. 创建子弹类
2.创建玩家飞机类
3. 创建敌机类
4.检查键盘输入
5.创建主模块
四、测试结果
五、思考、心得和改进以及不明白的问题
附录 所有代码如下:
一、课程设计目的及应用背景
根据课程要求,以及面向对象程序设计的编程思想,在Windows操作系统环境下,运用PyCharm编译程序,以Python语言为开发语言,最终实现飞机大战游戏相应的游戏操作功能。Python是一种跨平台的、开源的、免费的、解释型的高级编程语言。它具有丰富的、强大的库, 能够把其他语言制作的各种模块很轻松地联结在一起, 所以Python常被称为“胶水”语言。Python语言近几年发展势头迅猛, 应用领域也非常广泛, 在Web编程、图形处理、黑客编程、大数据处理、网络爬虫、科学计算和游戏编程等领域都能找到Python的应用。其中Pygame是Python的一个第三方库, 搭载了基于OpenGL的图形库和优质的音频库, 可以快速上手制作2D游戏的原型。Pygame的API比较偏底层, 开发人员在编程时具有很大的自由度, 同时具有了很强的可定制性。Python语言的研究和发明主要是为了便于学习和应用, 因此Python语言是开源的, 并且语法非常简单、容易编写和理解。本文通过对飞机大战游戏的设计与分析, 掌握Python语言在游戏开发领域的优势。
飞机大战游戏设计开发课题是《面向对象程序设计(Python)》中面向对象程序设计的一次运用,主要设计原则如下:
(1)简单性,在实现软件的功能的同时, 尽量让软件操作简单易懂;
(2)针对性,基于Python软件, 实现飞机大战游戏的各种要求;
(3)一致性,类型、变量和其他元素的命名规则保持一致;
完成同样的功能应该尽量使用同样的元素;界面元素的外观风格、摆放位置在同一个界面和不同界面之间是一致的。可以使其基本类库Pygame的基本函数和功能模块的调用操作实现python语言在课程设计中的运用。
通过对飞机大战游戏设计的实现,要求我们进一步理解和掌握课堂上所学各种基本类型的变量、数据类型、类、用户输入和文件操作实现面向对象的游戏开发,以及它们在程序中的使用方法;掌握Python软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力;掌握使用各种计算机资料和有关参考资料,提高我们进行程序设计的基本能力,逐步熟悉程序设计的方法,并养成良好的编程习惯。
本次设计为了使飞机大战游戏具有更加丰富的功能,基于面向对象和面向过程的方法,使用Python编程语言提供资源结构,以Pygame模块对游戏进行研发,提出了飞机大战游戏开发方案。通过各种优化调整,实现了飞机的飞行移动、击落,计分等功能,实现了飞机大战的开发,增加游戏体验。
二、课程设计内容
开发一款飞机大战游戏,要求:
(1)实现飞机的移动、子弹发射,对本次游戏有一个初步的编写及认识。
(2)飞机的持续按键移动和飞机自爆优化。
(3)进行基类的抽取,使代码更具有层次性和简化重复代码。
(4)对判断以及删除越界子弹、敌机发射子弹进行扩展优化。
三、课程设计代码实现
1. 创建子弹类
该项目可采用面向对象编程思路进行设计,对于不同的对象可设计3个不同的类,分别是子弹类、玩家飞机类和敌机类。
子弹类主要实现的功能是:显示子弹、子弹移动和处理子弹越界问题。
(1)显示子弹
首先需要确定显示子弹的位置,当按下空格键时,代表玩家飞机要发射一枚子弹,因此,需要在玩家飞机的顶部位置显示子弹。并且无论玩家飞机左右移动到什么位置,只要按下空格键,子弹生成的初始位置都位于玩家飞机的顶部。因此,子弹的初始位置与玩家飞机的位置相关。
首先可定义一个表示子弹的类Bullet,在该类中定义一个构造方法用于初始化数据,然后定义一个用于显示子弹的方法,具体代码如下。
#子弹类
class Bullet(object):
def __init__(self, screen_temp, x, y): #构造方法 初始化子弹对象的属性
self.x = x+40 #子弹起始X坐标
self.y = y-20 #子弹起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/bullet.png") #创建一个子弹图片
def display(self): #显示子弹图片的方法
self.screen.blit(self.image, (self.x, self.y)) #将创建的子弹图片按设定的坐标贴到窗口中
(2)子弹移动
在Bullet类中添加一个子弹移动的方法move,让子弹每移动一次,y值减10,具体代码如下。
#子弹移动方法
def move(self): #子弹移动方法
self.y-=10 #子弹Y坐标自减10
(3)处理子弹越界问题
在Bullet类中添加一个judge方法,用于判断子弹是否发射到屏幕以外,具体代码如下。
def judge(self): #判断子弹是否越界的方法
if self.y<0: #如果子弹的Y坐标小于0
return True #返回true正确
else:
return False #返回false错误
2.创建玩家飞机类
玩家飞机类中主要实现的功能是:显示玩家飞机、控制玩家飞机左右移动以及发射子弹。
(1)显示玩家飞机
在窗口中要显示玩家飞机,可以根据玩家飞机图片的名称创建图像,再把该图像显示到屏幕的设定位置。
首先定义一个表示玩家飞机的类Aircraft_obj,在该类中定义一个构造方法用于初始化数据,然后定义一个用于显示飞机的方法。在该类中还需要玩家飞机控制发射子弹,因此,在构造方法中还需要添加一个列表,用于存储玩家飞机发射的所有子弹,并且一旦遍历这个列表,就会将子弹显示到飞机对象的上方。具体代码如下。
#飞机类
class Aircraft_obj(object):
def __init__(self, screen_temp): #构造方法 初始化飞机对象的属性
self.x = 190 #飞起起始X坐标
self.y = 708 #飞机起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/hero1.png") #创建一个飞机图
self.bullet_list = []#存储发射出去的子弹对象引用
def display(self): #显示飞机图片的方法(这里包括了显示子弹的图片)
self.screen.blit(self.image, (self.x, self.y)) #将创建的飞机图片按设定的坐标贴到窗口中
#显示飞机发射的所有子弹
for bullet in self.bullet_list:
bullet.display() #显示子弹
bullet.move() #移动子弹
if bullet.judge():#判断子弹是否越界
self.bullet_list.remove(bullet) #将子弹从bullet_list中删除
(2)控制玩家飞机左右移动
玩家飞机具有向左移动和向右移动的功能,这两个功能可以通过在方法中改变坐标的x值进行实现。还需要控制飞机不能移出窗口。具体代码如下。
def move_left(self): #飞机左移方法
if self.x < 10: #X坐标小于10(移动距离)
pass #不做任何事
else:
self.x -= 10 #X坐标自减少10
def move_right(self): #飞机右移方法
if self.x > 480-100-10: #X坐标大于(窗口宽度-飞机宽度-移动距离)的值
pass #不做任何事
else:
self.x += 10 #坐标自增加10
(3)控制玩家飞机发射子弹
在玩家飞机类中创建fire()方法,将所有玩家飞机发射的子弹存储到飞机对象的属性列表中,具体代码如下。
#存储发射子弹的方法
def fire(self):
self.bullet_list.append(Bullet(self.screen, self.x, self.y)) #将发射的子弹对象存储到bullet_list中
3. 创建敌机类
敌机类中主要实现的功能是:显示敌机、敌机左右移动以及敌机被击中并爆炸。
(1)初始化敌机
跟玩家飞机类似,可定义一个表示敌机的类EnemyPlane。同样,敌机应该有默认的位置、呈现图像的窗口、敌机图片、在放爆炸图片的列表等属性,具体代码如下。
#敌机类
class EnemyPlane(object):
def __init__(self, screen_temp): #构造方法 初始化敌机对象的属性
self.x = 0 #敌机的起始X坐标
self.y = 0 #敌机的起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/enemy0.png") #创建一个敌机图片
self.direction = "right" #用来存储飞机移动方向,默认向右移动
#爆炸效果用的属性
self.hit = False #表示是否要爆炸
self.bomb_lists = [] #用来存储爆炸时需要的图片
self.__crate_images() #调用这个方法向bomb_lists中添加图片
self.image_num = 0#用来记录while循环的次数,当次数达到一定值时才显示一张爆炸的图,然后清空,当这个次数再次达到时,再显示下一个爆炸效果的图片
self.image_index = 0#用来记录当前要显示的爆炸效果的图片的序号
(2)敌机左右移动
当程序启动后,敌机开始在窗口的项部做直线运行,直到碰到屏幕的边缘后向反方向做真线运行。
可以为EnemyPlane(敌机)类添加一个移动敌机的方法move,在该方法中根据飞机移动的方向改变x对应的坐标值,再根据x的值限定敌机移动的范围,只要超过屏幕的宽度范围,就改变飞机运行的方向,具体代码如下。
def move(self): #敌机移动方法
if self.hit == True:
pass
else:
if self.direction=="right": #如果是向右移动
self.x += 5 #X坐标自增加5
elif self.direction=="left": #如果是向左移动
self.x -= 5 #X坐标自减少5
if self.x>480-50: #如果X坐标大于窗口减去敌机宽度的值
self.direction = "left" #移动方向改为左
elif self.x<0: #如果X坐标小于0
self.direction = "right" #移动方向改为右
(3)敌机爆炸
敌机被子弹击中后会爆炸,爆炸过程中所需要用到的图片保存在bomb lists列表中,此处可定义一个方法用于添加图片到列表中,具体代码如下。
def __crate_images(self): #将爆炸需要的图片添加到self.bomb_lists中
self.bomb_lists.append(pygame.image.load("./images/enemy0_down1.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down2.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down3.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down4.png"))
接下来定义一个判断爆炸的方法,只要满足以下3个条件中的任意一个即可实现爆炸:
(1)子弹横坐标在敌机横坐标的区域中,并且子弹y坐标小于敌机图片的高度;
(2)子弹最右侧坐标等于敌机最左侧坐标,并且子弹y坐标小于敌机图片的高度:
(3)子弹最左侧尘标等于敌机最右侧坐标,并且子弹y坐标小于敌机图片的高度。具体代码如下
#判断爆炸的方法,x1表示子弹最左侧的X坐标,x2表示子弹最右侧的X坐标,y表示子弹当前的Y坐标
def blast(self,x1,x2,y):
#判断子弹能命中敌机的三种情况,满足任意一种即可让敌机爆炸,51是敌机图片的宽度,39是敌机图片的高度
#1.子弹横坐标在敌机横坐标的区域中,并且子弹Y坐标小于敌机图片的高度
#2.子弹最右侧坐标等于敌机最左侧坐标,并且子弹Y坐标小于敌机图片的高度
#3.子弹最左侧坐标等于敌机最右侧坐标,并且子弹Y坐标小于敌机图片的高度
if ((x1>=self.x and x2<=self.x+51) or x2==self.x or x1==self.x+51) and y<39:
self.hit = True
显示敌机的方法与显示玩家飞机有所不同,需要判断是否已经被击中,如果已被击中,需要显示爆炸的图片后退出程序,如果没有被击中,显示敌机图片,具体代码如下。
def display(self): #显示敌机的方法
#如果被击中,就显示爆炸效果,否则显示普通的飞机效果
if self.hit == True: #如果满足爆炸条件,就显示爆炸的图片
self.screen.blit(self.bomb_lists[self.image_index], (self.x, self.y))
self.image_num+=1 #这是统计循环次数,为了使玩家看清爆炸效果
if self.image_num == 7: #如果循环次数达到7次
self.image_num=0 #将循环次数改为0次
self.image_index+=1 #图片显示序号+1,换为另一张图
if self.image_index>3: #这里爆炸图片一共是四张,所以是图片序号大于三次
time.sleep(1) #暂停一秒
exit() #调用exit让游戏退出
else: #否则显示正常的敌机图片
self.screen.blit(self.image,(self.x, self.y))
4.检查键盘输入
如果想要获取键盘和鼠标产生的事件,就需要使用for循环遍历事件列表,取出每个事件与eventtype《事件类型)进行比较。如果event.type的值为QUIT,表示用户按下关闭按钮,此时就要退出程序:如果event.type的值为KEYDOWN,表示用户使用了键盘,需要判断按下的是哪个键,然后进行键盘事件的处理。具体代码如下。
#处理鼠标和键盘事件的方法
def key_control(aircraft_temp):
#获取当前等待处理的事件,使用for循环来遍历里面的事件
for event in pygame.event.get():
#判断是否点击了退出按钮
if event.type == QUIT:
print("exit") #输出“exit”
exit() #退出窗口
#判断是不是键盘按下事件
elif event.type == KEYDOWN:
#检测按键是不是a或者left
if event.key == K_a or event.key == K_LEFT:
print('left') #输出“left”
aircraft_temp.move_left() #执行飞机左移方法
#检测按键是不是d或者right
elif event.key == K_d or event.key == K_RIGHT:
print('right') #输出“right”
aircraft_temp.move_right() #执行飞机右移方法
#检测按键是不是空格键
elif event.key == K_SPACE:
print('space') #输出“space”
aircraft_temp.fire() #执行飞机类中存储子弹的方法
5.创建主模块
飞机大战的整个场景需要一个窗口作为载体,显示游戏中的画面。这里准备了一张图片用作游戏界面的背景,并在窗口中进行显示。
在主模块中,需要创建玩家飞机对象和敌机对象、显示各个对象、判断敌机是否被击中、调用敌机移动方法让敌机移动、调用事件处理函数进行事件处理。具体代码如下。
import pygame #导入pygame模块
from pygame.locals import * #导入pygame.locals模块
import time #导入time模块
def main():
#1. 创建窗口
pygame.init()
screen = pygame.display.set_mode((480,852),0,32)
#2. 创建一个背景图片
background = pygame.image.load("./images/background.png")
#3. 创建一个飞机对象
aircraft = Aircraft_obj(screen)
#4. 创建一个敌机对象
enemy = EnemyPlane(screen)
while True:
screen.blit(background, (0,0)) #把背景复制到窗口的0,0处开始贴进去
aircraft.display() #执行飞机类中显示飞机的方法
for bullet in aircraft.bullet_list: #循环飞机对象中存储的子弹信息
x1 = bullet.x #子弹当前X坐标
x2 = bullet.x + 22 #子弹当前X坐标+子弹图片的宽
y1 = bullet.y #子弹当前Y坐标
enemy.blast(x1,x2,y1) #判断子弹的坐标区域有没有与敌机相交
enemy.display() #执行敌机类中显示敌机的方法
enemy.move() #调用敌机的移动方法
pygame.display.update() #更新需要显示的内容到窗口
key_control(aircraft) #处理飞机对象的相关事件
time.sleep(0.01) #暂停0.01秒
main()
四、测试结果
五、思考、心得和改进以及不明白的问题
本次课题研究是基于兴趣爱好的一次实践,兴趣爱好给予了我很大的动力,这也使我在遇到各种问题时,总能通过多种渠道找到解决方案。虽然是第一次使用Python开发游戏,在一边进行学习,一边进行游戏开发和设计过程中,遇到了很多问题,也走了不少弯路,但锻炼了自我解决问题的能力。这次课题研究不仅让我对Python有了进一步的了解,而且还大大提高了编程能力,锻炼了自己的逻辑思维和整体设计的能力,收获颇多。
通过这次课题研究,我意识到完整的软件开发思路是非常重要的,它关系到我们开发过程能否顺利实现。在项目开始之前,必须有软件工程的系统化的知识体系,不仅如此,还应包括软件结构位置、代码编写和模块划分和整体布局,只有做完这些步骤,才能逐步开发出想要实现的功能。这样定能达到事半功倍的效果。
整个软件按照计划大致实现了游戏的具体功能,虽然游戏能正常运行,不过因所学知识及开发周期有限,还有很多需要改进的地方,有待于日后进一步的改进和完善。这个游戏的实现,我是跟着网上的教学思路学着做的,我觉得实现这个飞机大战的也运用到了很多知识,通过这次实验,我对Python的理解也更加深刻。我觉得这个游戏的实现还是有一些不足的,例如没有实现多种子弹,随机道具拾取等等。
附录 所有代码如下:
# -*- coding:utf-8 -*-
import pygame #导入pygame模块
from pygame.locals import * #导入pygame.locals模块
import time #导入time模块
#子弹类
class Bullet(object):
def __init__(self, screen_temp, x, y): #构造方法 初始化子弹对象的属性
self.x = x+40 #子弹起始X坐标
self.y = y-20 #子弹起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/bullet.png") #创建一个子弹图片
def display(self): #显示子弹图片的方法
self.screen.blit(self.image, (self.x, self.y)) #将创建的子弹图片按设定的坐标贴到窗口中
def move(self): #子弹移动方法
self.y-=10 #子弹Y坐标自减10
def judge(self): #判断子弹是否越界的方法
if self.y<0: #如果子弹的Y坐标小于0
return True #返回true正确
else:
return False #返回false错误
#飞机类
class Aircraft_obj(object):
def __init__(self, screen_temp): #构造方法 初始化飞机对象的属性
self.x = 190 #飞起起始X坐标
self.y = 708 #飞机起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/hero1.png") #创建一个飞机图
self.bullet_list = []#存储发射出去的子弹对象引用
def display(self): #显示飞机图片的方法(这里包括了显示子弹的图片)
self.screen.blit(self.image, (self.x, self.y)) #将创建的飞机图片按设定的坐标贴到窗口中
#显示飞机发射的所有子弹
for bullet in self.bullet_list:
bullet.display() #显示子弹
bullet.move() #移动子弹
if bullet.judge():#判断子弹是否越界
self.bullet_list.remove(bullet) #将子弹从bullet_list中删除
def move_left(self): #飞机左移方法
if self.x < 10: #X坐标小于10(移动距离)
pass #不做任何事
else:
self.x -= 10 #X坐标自减少10
def move_right(self): #飞机右移方法
if self.x > 480-100-10: #X坐标大于(窗口宽度-飞机宽度-移动距离)的值
pass #不做任何事
else:
self.x += 10 #坐标自增加10
#存储发射子弹的方法
def fire(self):
self.bullet_list.append(Bullet(self.screen, self.x, self.y)) #将发射的子弹对象存储到bullet_list中
#敌机类
class EnemyPlane(object):
def __init__(self, screen_temp): #构造方法 初始化敌机对象的属性
self.x = 0 #敌机的起始X坐标
self.y = 0 #敌机的起始Y坐标
self.screen = screen_temp #窗口
self.image = pygame.image.load("./images/enemy0.png") #创建一个敌机图片
self.direction = "right" #用来存储飞机移动方向,默认向右移动
#爆炸效果用的属性
self.hit = False #表示是否要爆炸
self.bomb_lists = [] #用来存储爆炸时需要的图片
self.__crate_images() #调用这个方法向bomb_lists中添加图片
self.image_num = 0#用来记录while循环的次数,当次数达到一定值时才显示一张爆炸的图,然后清空,当这个次数再次达到时,再显示下一个爆炸效果的图片
self.image_index = 0#用来记录当前要显示的爆炸效果的图片的序号
def __crate_images(self): #将爆炸需要的图片添加到self.bomb_lists中
self.bomb_lists.append(pygame.image.load("./images/enemy0_down1.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down2.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down3.png"))
self.bomb_lists.append(pygame.image.load("./images/enemy0_down4.png"))
#判断爆炸的方法,x1表示子弹最左侧的X坐标,x2表示子弹最右侧的X坐标,y表示子弹当前的Y坐标
def blast(self,x1,x2,y):
#判断子弹能命中敌机的三种情况,满足任意一种即可让敌机爆炸,51是敌机图片的宽度,39是敌机图片的高度
#1.子弹横坐标在敌机横坐标的区域中,并且子弹Y坐标小于敌机图片的高度
#2.子弹最右侧坐标等于敌机最左侧坐标,并且子弹Y坐标小于敌机图片的高度
#3.子弹最左侧坐标等于敌机最右侧坐标,并且子弹Y坐标小于敌机图片的高度
if ((x1>=self.x and x2<=self.x+51) or x2==self.x or x1==self.x+51) and y<39:
self.hit = True
def display(self): #显示敌机的方法
#如果被击中,就显示爆炸效果,否则显示普通的飞机效果
if self.hit == True: #如果满足爆炸条件,就显示爆炸的图片
self.screen.blit(self.bomb_lists[self.image_index], (self.x, self.y))
self.image_num+=1 #这是统计循环次数,为了使玩家看清爆炸效果
if self.image_num == 7: #如果循环次数达到7次
self.image_num=0 #将循环次数改为0次
self.image_index+=1 #图片显示序号+1,换为另一张图
if self.image_index>3: #这里爆炸图片一共是四张,所以是图片序号大于三次
time.sleep(1) #暂停一秒
exit() #调用exit让游戏退出
else: #否则显示正常的敌机图片
self.screen.blit(self.image,(self.x, self.y))
def move(self): #敌机移动方法
if self.hit == True:
pass
else:
if self.direction=="right": #如果是向右移动
self.x += 5 #X坐标自增加5
elif self.direction=="left": #如果是向左移动
self.x -= 5 #X坐标自减少5
if self.x>480-50: #如果X坐标大于窗口减去敌机宽度的值
self.direction = "left" #移动方向改为左
elif self.x<0: #如果X坐标小于0
self.direction = "right" #移动方向改为右
#处理鼠标和键盘事件的方法
def key_control(aircraft_temp):
#获取当前等待处理的事件,使用for循环来遍历里面的事件
for event in pygame.event.get():
#判断是否点击了退出按钮
if event.type == QUIT:
print("exit") #输出“exit”
exit() #退出窗口
#判断是不是键盘按下事件
elif event.type == KEYDOWN:
#检测按键是不是a或者left
if event.key == K_a or event.key == K_LEFT:
print('left') #输出“left”
aircraft_temp.move_left() #执行飞机左移方法
#检测按键是不是d或者right
elif event.key == K_d or event.key == K_RIGHT:
print('right') #输出“right”
aircraft_temp.move_right() #执行飞机右移方法
#检测按键是不是空格键
elif event.key == K_SPACE:
print('space') #输出“space”
aircraft_temp.fire() #执行飞机类中存储子弹的方法
def main():
#1. 创建窗口
pygame.init()
screen = pygame.display.set_mode((480,852),0,32)
#2. 创建一个背景图片
background = pygame.image.load("./images/background.png")
#3. 创建一个飞机对象
aircraft = Aircraft_obj(screen)
#4. 创建一个敌机对象
enemy = EnemyPlane(screen)
while True:
screen.blit(background, (0,0)) #把背景复制到窗口的0,0处开始贴进去
aircraft.display() #执行飞机类中显示飞机的方法
for bullet in aircraft.bullet_list: #循环飞机对象中存储的子弹信息
x1 = bullet.x #子弹当前X坐标
x2 = bullet.x + 22 #子弹当前X坐标+子弹图片的宽
y1 = bullet.y #子弹当前Y坐标
enemy.blast(x1,x2,y1) #判断子弹的坐标区域有没有与敌机相交
enemy.display() #执行敌机类中显示敌机的方法
enemy.move() #调用敌机的移动方法
pygame.display.update() #更新需要显示的内容到窗口
key_control(aircraft) #处理飞机对象的相关事件
time.sleep(0.01) #暂停0.01秒
main()
图片资源