目录

一、课程设计目的及应用背景

二、课程设计内容

三、课程设计代码实现

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坐标小于0return 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  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:passelse:if self.direction=="right": #如果是向右移动self.x += 5 #X坐标自增加5elif self.direction=="left": #如果是向左移动self.x -= 5 #X坐标自减少5if self.x>480-50: #如果X坐标大于窗口减去敌机宽度的值self.direction = "left" #移动方向改为左elif self.x<0: #如果X坐标小于0self.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或者leftif event.key == K_a or event.key == K_LEFT:print('left') #输出“left”aircraft_temp.move_left() #执行飞机左移方法#检测按键是不是d或者rightelif 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坐标自减10def judge(self):#判断子弹是否越界的方法if self.y<0:#如果子弹的Y坐标小于0return 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  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坐标defblast(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 y3:#这里爆炸图片一共是四张,所以是图片序号大于三次time.sleep(1) #暂停一秒exit()#调用exit让游戏退出else: #否则显示正常的敌机图片self.screen.blit(self.image,(self.x, self.y))def move(self): #敌机移动方法if self.hit == True: passelse:if self.direction=="right": #如果是向右移动self.x += 5 #X坐标自增加5elif self.direction=="left":#如果是向左移动self.x -= 5 #X坐标自减少5if self.x>480-50: #如果X坐标大于窗口减去敌机宽度的值self.direction = "left" #移动方向改为左elif self.x<0:#如果X坐标小于0self.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或者leftif event.key == K_a or event.key == K_LEFT:print('left') #输出“left”aircraft_temp.move_left() #执行飞机左移方法#检测按键是不是d或者rightelif 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()

图片资源