Python语言程序设计课程论文
项目名称:飞机大战
姓名:陆海波
学号:171110035
班级:1701
成绩:
博客链接:
摘要
飞机大战是一个很经典的大众游戏,这个学期我学习了关于Python的很多知识,所以我用Python做了这个游戏,在这个游戏中,我实现了游戏背景图片的移动效果,背景音乐和飞机中弹后的一个爆炸音效,还有敌机的产生,子弹的发射,飞机中弹销毁和计算得分等功能。
目录
1.引言... 4
1.1背景... 4
1.2意义... 4
1.3相关研究... 4
1.4实现的功能... 4
2. 系统结构... 5
3. 实现代码... 6
4. 实验... 18
5. 总结和展望... 20
1.引言
1.1背景
飞机大战是一个很经典的大众游戏,在学习了一个学期的Python之后,我决定使用Python来学习和实现这个游戏。
1.2意义
我觉得做这个游戏的意义就是要体现这个学期所学到的关于Python的知识。
1.3相关研究
由于我比较喜欢游戏方面的,因此我就在网上学习了Pygame,Pygame是一个游戏的开发库,包括了图形、动画、声音以及键盘鼠标的控制。
每个游戏的核心都是一个循环,将其称为“游戏循环”。这个循环一直在不断运行,一遍又一遍地完成游戏工作所需的所有事情。每次循环显示一次游戏当前画面,称为帧。
Pygame的游戏循环,主要处理3件事情:
①处理外部输入(鼠标点击或键盘按下事件)
②更新游戏对象的状态
③游戏画面的渲染
另外Pygame还有一个时钟,它可以控制游戏循环的快慢,也就是我们平时玩王者荣耀和吃鸡的帧率FPS。
1.4实现的功能
实现了背景图片的滚动效果,背景音乐和飞机爆炸音效,敌机的产生,子弹的发射,飞机中弹销毁和计算得分等功能
2. 系统结构
游戏的总框架如图1所示:
图1 游戏总框架
这个游戏的实现使用了Pygame模块。实现功能的原理如下表1所示:
功能原理
背景图片滚动用两张相同的的图片不断地进行进行重画
背景音乐和飞机爆炸音效用pygame.mixer来播放背景音乐与飞机的爆炸音效
子弹的发射在飞机头部坐标绘制子弹,然后重画子弹的移动位置
敌机产生每隔一定时间在屏幕上方随机位置绘制敌机
飞机中弹销毁不断地检测我方飞机是否和敌机或者敌机子弹是否碰撞,碰撞后轮播爆炸效果图
得分计算每次击中敌机分数+1
表1 功能原理
类图如图2所示:
图2 类图
3. 实现代码
首先,需要引进实现这款游戏所需要用到的模块
import pygame
import sys
from pygame.locals import *
import time
import random
import copy
设计背景类,绘制背景图片,实现背景图片的滚动效果
# 背景图片
class GameBackground:
image1 = None
image2 = None
main_scene =None
y1 = None
y2 = None
#初始化背景图片
def__init__(self, scene):
#加载相同张图片资源,做交替实现背景图片滚动
self.image1 = pygame.image.load("images/plane/map.jpg")
self.image2 = copy.copy(self.image1)
#保存场景对象
self.main_scene = scene
#辅助移动背景图片
self.y1 =0
self.y2 =-self.main_scene.size[1]
#计算地图图片绘制坐标
defaction(self):
self.y1 =self.y1 + 1
self.y2 =self.y2 + 1
if self.y1>= self.main_scene.size[1]:
self.y1 = 0
if self.y2>= 0:
self.y2 = -self.main_scene.size[1]
#绘制地图的两张图片
defdraw(self):
self.main_scene.scene.blit(self.image1, (0, self.y1))
self.main_scene.scene.blit(self.image2, (0, self.y2))
设计我方飞机的子弹类,固定飞行速度为10
# 子弹
class Bullet:
speed = 10
x = None
y = None
width = None
hieght = None
def__init__(self, x, y, w, h):
self.x = x
self.y = y
self.width= w
self.height = h
defmove(self):
self.y -=self.speed
设计敌方飞机的子弹类,敌方飞机的子弹飞行速度为7到15的随机值
# 敌机子弹
class EnemyBullet:
speed = None
x = None
y = None
width = None
hieght = None
def__init__(self, x, y, w, h):
self.x = x
self.y = y
self.width= w
self.height = h
self.speed= random.randint(7, 15)
defmove(self):
self.y +=self.speed
设计飞机类,实现飞机的移动,子弹的发射等功能
# 飞机
class Plane:
x = None
y = None
image = []
main_scene =None
speed = 8
style = 0
width = None
height = None
shoot_frequency = 0
bullet_image =None
bullets = []
boom = None
isHit = False
def__init__(self, scene):
#加载飞机外观图片
self.image.append(pygame.image.load("images/plane/plane.png"))
self.image.append(pygame.image.load("images/plane/plane_left.png"))
self.image.append(pygame.image.load("images/plane/plane_right.png"))
#加载飞机子弹图片
self.bullet_image = pygame.image.load("images/plane/bullet.png")
self.main_scene = scene
self.x =self.main_scene.size[0] / 2 - self.image[self.style].get_width() / 2
self.y =600
self.width= self.image[self.style].get_width()
self.height = self.image[self.style].get_height()
#发射子弹
defshoot(self):
ifself.shoot_frequency % 15 == 0:
bullet_x = self.x + self.image[self.style].get_width() // 2 -self.bullet_image.get_width() // 2
bullet_y = self.y - self.bullet_image.get_height() + 10
b_w =self.bullet_image.get_width()
b_h =self.bullet_image.get_height()
self.bullets.append(Bullet(bullet_x, bullet_y, b_w, b_h))
self.main_scene.bullet_sound.play()
self.shoot_frequency += 1
ifself.shoot_frequency >= 15:
self.shoot_frequency = 0
#绘制子弹
defdrawBullets(self):
for b inself.bullets[:]:
b.move()
if b.y< 0:
self.bullets.remove(b)
self.main_scene.scene.blit(self.bullet_image, (b.x, b.y))
#向上
defmoveUp(self):
if self.y > 0:
self.y-= self.speed
#向下
defmoveDown(self):
if self.y+ self.image[self.style].get_height() < self.main_scene.size[1]:
self.y+= self.speed
#向左
defmoveLeft(self):
if self.x> 0:
self.x-= self.speed
#向右
defmoveRight(self):
if self.x+ self.image[self.style].get_width() < self.main_scene.size[0]:
self.x+= self.speed
#绘制飞机
defdraw(self):
self.main_scene.scene.blit(self.image[self.style],(self.x, self.y))
#设置击中状态
defsetHit(self, hit):
self.isHit= hit
if hit:
self.main_scene.game_music.stop()
self.main_scene.over_sound.play()
else:
self.x = self.main_scene.size[0] / 2 -self.image[self.style].get_width() / 2
self.y= 600
self.bullets.clear()
设计敌方飞机类,给敌方飞机设计一个移动轨迹
# 敌机
class Enemy:
image = None
x = None
y = None
speed = 5
width = None
hieght = None
def__init__(self, image, init_pos):
self.image= image
self.x =init_pos[0]
self.y =init_pos[1]
self.width= self.image.get_width()
self.height = self.image.get_height()
def move(self):
self.y +=self.speed
设计爆炸类,用轮播图实现飞机销毁后的爆炸效果
# 爆炸效果
class Boom:
x = None
y = None
main_scene =None
image_index =0 #效果图片播放索引
def__init__(self, init_pos, scene):
self.x =init_pos[0]
self.y =init_pos[1]
self.main_scene = scene
def show(self,images):
ifself.image_index < len(images) - 1:
self.main_scene.scene.blit(images[self.image_index], (self.x, self.y))
self.image_index += 1
设计主场景类,设置游戏窗口的大小和标题等,实现飞机、子弹图片和背景音乐的加载,然后绘制图片,实现碰撞检测以及得分计算还有键盘事件的处理,以及游戏结束事件。
# 主场景
class MainScene:
size = None
scene = None
bg = None
plane = None
timer = None
running = True
enemy_images =[]
enemies = []
enemy_bullet =None
enemy_bullets= []
enemy_frequency = 0
boom_images =[]
booms = []
score = 0
game_over_image = None
boom_sound =None
game_music =None
bullet_sound =None
enemy_bullet_sound = None
over_sound =None
#初始化主场景
def__init__(self):
#初始化 pygame,使用自定义字体必须用到
pygame.init()
#场景尺寸
self.size= (458, 752)
#场景对象
self.scene= pygame.display.set_mode([self.size[0], self.size[1]])
#设置标题
pygame.display.set_caption("飞机大战")
#创建clock对象控制帧数
self.timer= pygame.time.Clock()
#创建地图对象
self.bg =GameBackground(self)
#创建飞机对象
self.plane= Plane(self)
#加载敌机外形图片
for n inrange(4):
self.enemy_images.append(pygame.image.load("images/plane/enemy/e_"+ str(n + 1) + ".png"))
#加载敌机子弹图片
self.enemy_bullet = pygame.image.load("images/plane/enemy_bullet.png")
#缩小敌机子弹图片为原来的一半
new_size =(self.enemy_bullet.get_width() // 2, self.enemy_bullet.get_height() // 2)
self.enemy_bullet = pygame.transform.scale(self.enemy_bullet, new_size)
#加载爆炸效果图片
for n inrange(6):
self.boom_images.append(pygame.image.load("images/plane/boom/b"+ str(n + 1) + ".png"))
# GameOver的背景图
self.game_over_image =pygame.image.load("images/plane/gameover.png")
#加载声音文件
self.game_music = pygame.mixer.Sound("music/game_music.wav")
self.boom_sound = pygame.mixer.Sound("sounds/plane/boom.wav")
self.bullet_sound =pygame.mixer.Sound("sounds/plane/bullet.wav")
self.enemy_bullet_sound = pygame.mixer.Sound("sounds/plane/enemy_bullet.wav")
self.over_sound =pygame.mixer.Sound("sounds/plane/game_over.wav")
self.game_music.play(-1)
#重置场景数据
defreset(self):
self.enemies.clear()
self.booms.clear()
self.enemy_bullets.clear()
self.score= 0
self.game_music.play(-1)
#绘制
defdraw_elements(self):
if notself.plane.isHit:
self.bg.draw() #绘制背景
self.plane.draw() #绘制飞机
self.plane.drawBullets() #绘制飞机子弹
#绘制敌机移动
for ein self.enemies:
self.scene.blit(e.image, (e.x, e.y))
#绘制敌机子弹移动
for ebin self.enemy_bullets:
self.scene.blit(self.enemy_bullet, (eb.x, eb.y))
#绘制敌机爆炸效果
for bin self.booms[:]:
b.show(self.boom_images)
ifb.image_index == len(self.boom_images) - 1:
self.booms.remove(b)
#绘制得分
font =pygame.font.Font("fonts/katong.ttf", 30)
text =font.render("分数:"+ str(self.score), True, (255, 255, 255))
text_rect = text.get_rect()
text_rect.centerx = self.scene.get_rect().centerx
text_rect.centery = 20
self.scene.blit(text, text_rect)
else:
if notself.plane.boom:
self.plane.boom = Boom([self.plane.x, self.plane.y], self)
self.plane.boom.show(self.boom_images)
ifself.plane.boom.image_index == len(self.boom_images) - 1:
#绘制最终得分文字
font = pygame.font.Font("fonts/katong.ttf", 30)
text = font.render("本次得分:"+ str(self.score), True, (255, 0, 0))
text_rect = text.get_rect()
text_rect.centerx = self.scene.get_rect().centerx
text_rect.centery = self.scene.get_rect().centery + 24
#绘制重新开始文字
text2 = font.render("按下回车重新开始", True, (255, 0, 0))
text_rect2 = text2.get_rect()
text_rect2.centerx = self.scene.get_rect().centerx
text_rect2.centery = self.scene.get_rect().centery + 200
#绘制游戏结束界面
self.scene.blit(self.game_over_image, (0, 0))
self.scene.blit(text, text_rect)
self.scene.blit(text2, text_rect2)
#计算元素坐标及生成元素
defaction_elements(self):
if notself.plane.isHit:
self.bg.action()
#生成敌机,需要控制生成频率
ifself.enemy_frequency % 50 == 0:
enemy_image = self.enemy_images[random.randint(0, len(self.enemy_images)- 1)]
#缩小敌机图片为原来的一半
new_size = (enemy_image.get_width() // 2, enemy_image.get_height() // 2)
enemy_image = pygame.transform.scale(enemy_image, new_size)
#设置敌机随机外观
enemy_pos = [random.randint(0, self.size[0] - enemy_image.get_width()),0]
enemy = Enemy(enemy_image, enemy_pos)
self.enemies.append(enemy)
#生成敌机子弹,需要控制生成频率
ret = random.randint(1, 100)
if ret >= 1 and ret <= 65: # 65%概率发射子弹
w = self.enemy_bullet.get_width()
h = self.enemy_bullet.get_height()
b_x = enemy.x + enemy.width // 2 - w // 2
b_y = enemy.y + enemy.height
self.enemy_bullets.append(EnemyBullet(b_x, b_y, w, h))
self.enemy_bullet_sound.play()
self.enemy_frequency += 1
ifself.enemy_frequency >= 100:
self.enemy_frequency = 0
#计算敌机坐标
for ein self.enemies[:]:
e.move()
ife.y > self.size[1]:
self.enemies.remove(e)
#计算敌机子弹坐标
for ebin self.enemy_bullets[:]:
eb.move()
ifeb.y > self.size[1]:
self.enemy_bullets.remove(eb)
#处理事件
defhandle_event(self):
for eventin pygame.event.get():
#检测松开键盘事件
if event.type== pygame.KEYUP:
#检测松开的按键是否是方向键左
ifevent.key == K_LEFT or event.key == K_RIGHT:
self.plane.style = 0
#检测到事件为退出时
ifevent.type == pygame.QUIT:
self.running = False
#碰撞检测
defdetect_collision(self):
if notself.plane.isHit:
for ein self.enemies[:]:
#敌机是否被飞机子弹击中
for b in self.plane.bullets[:]:
if self.collision(e, b) or self.collision(b, e):
self.enemies.remove(e)
self.plane.bullets.remove(b)
self.booms.append(Boom([e.x, e.y], self))
self.score += 1
self.boom_sound.play()
#敌机是否碰到飞机
if self.collision(e, self.plane)or self.collision(self.plane, e):
self.plane.setHit(True)
break
#敌机子弹是否击中飞机
for ebin self.enemy_bullets[:]:
ifself.collision(eb, self.plane) or self.collision(self.plane, eb):
self.plane.setHit(True)
break
#验证是否碰撞
defcollision(self, a, b):
temp1 =(b.x <= a.x + a.width <= b.x + b.width)
temp2 =(b.y <= a.y + a.height <= b.y + b.height)
returntemp1 and temp2
#处理按键
defkey_pressed(self):
#获取按下按键信息
key_pressed = pygame.key.get_pressed()
if notself.plane.isHit:
ifkey_pressed[K_UP]:
self.plane.moveUp()
ifkey_pressed[K_DOWN]:
self.plane.moveDown()
ifkey_pressed[K_LEFT]:
self.plane.style = 1
self.plane.moveLeft()
ifkey_pressed[K_RIGHT]:
self.plane.style = 2
self.plane.moveRight()
ifkey_pressed[K_SPACE]:
self.plane.shoot()
else:
ifkey_pressed[K_RETURN]:
#重置游戏数据
self.plane.setHit(False)
self.reset()
#处理帧数
defset_fps(self):
#刷新显示
pygame.display.update()
#设置帧率为60fps
self.timer.tick(60)
#主循环,主要处理各种事件
defrun_scene(self):
whileself.running:
#计算元素坐标及生成元素
self.action_elements()
#绘制元素图片
self.draw_elements()
#处理事件
self.handle_event()
#碰撞检测
self.detect_collision()
#按键处理
self.key_pressed()
#更新画布设置fps
self.set_fps()
forevent in pygame.event.get():
ifevent.type == pygame.QUIT:
pygame.quit()
sys.exit()
编写main函数,开始游戏
if __name__ == "__main__":
#创建主场景
mainScene =MainScene()
#开始游戏
mainScene.run_scene()
4. 实验
5. 总结和展望
这个游戏的实现,我是跟着网上的教学思路学着做的,我觉得实现这个飞机大战的也运用到了很多知识,通过这次实验,我对Python的理解也更加深刻。我觉得这个游戏的实现还是有一些不足的,例如没有实现多种子弹,随机道具拾取等等。