学习Python,最好的办法是实战,实战!我们知道,有无数的先人和大侠提供了非常多的软件包供我们选用。有时候学习是一件很枯燥的事,玩游戏就不一样了。我们玩的最多的游戏是别人开发的,能不能开发出一款自己的游戏呢?当然大型游戏是不太现实的,用二三天事件写一个飞机大战的游戏还是有可能的。
直接上效果图,由于自己一边玩一边抓图,可能抓不出最好的效果,先上两张吧。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200519174555107.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dhc19hX2NvZGVy,size_16,color_FFFFFF,t_70#pic_center
好了,为什么要上图呢?都说有图有真相,对吧,不然大家以为你嘴把式。其实这里上图不光是有图有真相,而是让大家看看游戏中大概有哪些元素。
好了,有哪些元素呢?我放飞机(可以有多种)、敌方不同种类的飞机,发射不同的子弹或导弹,敌机坠毁后可能掉出来弹药包啊,医药包啊啥的,英雄战机能捡到就可以用。捡不到就浪费了。背景是流动的星空,哪些白点星星向下按照不同的速度移动,营造出战机在太空的氛围(为了更好的太空氛围,有兴趣的朋友可以自己调试一下相关参数,一定会有更逼真的效果)。
小结一下,飞机大战的元素有如下几点:
1、英雄战机
2、敌机
3、英雄战机发射的子弹(可能有子弹、导弹、核弹等),当然敌机只能发射子弹和导弹。不然危机时刻咋干他呢?
4、敌机掉出来的宝贝(各种啊,可以自己配制添加)
5、星空背景
当然,现在还没有说相关统计、得分啊什么的,有兴趣的朋友可以看完后自己添加。位置都留好了,窗口最上方一条高度为xx像素的空间已经留好了。哈哈
简单说一下,这个游戏也是用了 pygame的Layer 功能,不清楚的朋友可以看我上一篇文章(Python:模拟windows命令按钮——一文学习Pygame分层显示)了解一下,非常简单。
为了程序的可扩展性和可读性,对飞机、子弹等使用配置文件给出相关参数,有兴趣的朋友可以通过扩展配置文件增加飞机种类、子弹类型等,让自己的游戏更加炫酷,而不需要更改任何代码。
部分配置文件如下:
IMAGE_PATH = "assets/images/"
ENEMY_BULLETS_TYPE = {1: 'EBULLET_1', 2: 'EBULLET_2'}
ENEMY_MISSILE_TYPE = {11: 'EMISSILE_1'}
HERO_BULLETS_TYPE = {21: 'HBULLET_1', 22: 'HBULLET_2', 23: 'P_BULLET'}
HERO_MISSILES_TYPE = {31: 'HMISSILE_1', 32: 'HMISSILE_2'}
HERO_NECLEAR_TYPE = {41: 'NUCLEAR'}
BULLETS = {
'EBULLET_1' : {'IMAGE': 'enemy_B01.png', 'SPEED': 16, 'DESTROY_VALUE': 10, 'SP_FACTOR': 1, 'LAYER': 10},
'EBULLET_2' : {'IMAGE': 'enemy_B02.png', 'SPEED': 16, 'DESTROY_VALUE': 10, 'SP_FACTOR': 1, 'LAYER': 10},
'EMISSILE_1': {'IMAGE': 'enemy_M01.png', 'SPEED': 16, 'DESTROY_VALUE': 50, 'SP_FACTOR': 1, 'LAYER': 10},
'HBULLET_1' : {'IMAGE': 'hero_B01.png', 'SPEED': -22, 'DESTROY_VALUE': 30, 'SP_FACTOR': 1, 'LAYER': 10},
'HBULLET_2' : {'IMAGE': 'hero_B02.png', 'SPEED': -22, 'DESTROY_VALUE': 30, 'SP_FACTOR': 1, 'LAYER': 10},
'P_BULLET': {'IMAGE': 'hero_BP.png', 'SPEED': -22, 'DESTROY_VALUE': 60, 'SP_FACTOR': 1, 'LAYER': 10},
'HMISSILE_1': {'IMAGE': 'hero_M01.png', 'SPEED': -25, 'DESTROY_VALUE': 120, 'SP_FACTOR': 1, 'LAYER': 10},
'HMISSILE_2': {'IMAGE': 'hero_M02.png', 'SPEED': -25, 'DESTROY_VALUE': 120, 'SP_FACTOR': 1, 'LAYER': 10},
'NUCLEAR' : {'IMAGE': 'hero_N01.png', 'SPEED': -30, 'DESTROY_VALUE': 99999, 'SP_FACTOR': 1, 'LAYER': 10}}
ENEMY_PLANES = {
'ENEMY_F01': {'IMAGE': 'enemy_F01.png', 'DEFENCE': 100, 'X_SPD': 6, 'Y_SPD': 10, 'B_COUNT': 2, 'M_COUNT': 0, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 500},
'ENEMY_F02': {'IMAGE': 'enemy_F02.png', 'DEFENCE': 110, 'X_SPD': 6, 'Y_SPD': 12, 'B_COUNT': 1, 'M_COUNT': 0, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 400},
'ENEMY_F03': {'IMAGE': 'enemy_F03.png', 'DEFENCE': 120, 'X_SPD': 6, 'Y_SPD': 14, 'B_COUNT': 2, 'M_COUNT': 1, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 500},
'ENEMY_F04': {'IMAGE': 'enemy_F04.png', 'DEFENCE': 130, 'X_SPD': 6, 'Y_SPD': 15, 'B_COUNT': 2, 'M_COUNT': 0, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 600},
'ENEMY_F05': {'IMAGE': 'enemy_F05.png', 'DEFENCE': 140, 'X_SPD': 6, 'Y_SPD': 13, 'B_COUNT': 1, 'M_COUNT': 0, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 700},
'ENEMY_F06': {'IMAGE': 'enemy_F06.png', 'DEFENCE': 150, 'X_SPD': 6, 'Y_SPD': 11, 'B_COUNT': 2, 'M_COUNT': 0, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 500},
'ENEMY_F07': {'IMAGE': 'enemy_F07.png', 'DEFENCE': 160, 'X_SPD': 6, 'Y_SPD': 12, 'B_COUNT': 2, 'M_COUNT': 1, 'SP_FACTOR': 0.5, 'LAYER': 20, 'COLLISION': 600}}
HERO_PLANES = {
'HERO_F01': {'IMAGE': 'hero_F01.png', 'DEFENCE': 9999, 'X_SPD': 50, 'Y_SPD': 20, 'B_COUNT': 4, 'M_COUNT': 1, 'SP_FACTOR': 1, 'QUANTITY': 3, 'LAYER': 30},
'HERO_F02': {'IMAGE': 'hero_F02.png', 'DEFENCE': 9999, 'X_SPD': 50, 'Y_SPD': 20, 'B_COUNT': 2, 'M_COUNT': 2, 'SP_FACTOR': 1, 'QUANTITY': 3, 'LAYER': 30},
'HERO_F03': {'IMAGE': 'hero_F03.png', 'DEFENCE': 9999, 'X_SPD': 50, 'Y_SPD': 20, 'B_COUNT': 4, 'M_COUNT': 1, 'SP_FACTOR': 1, 'QUANTITY': 3, 'LAYER': 30}}
HERO_PLANE_MOVE = {K_a: 'GO_LEFT', K_w: 'GO_UP', K_s: 'GO_DOWN', K_d: 'GO_RIGHT'}
HERO_PLANE_SHOOT = {K_j: 'BULLET', K_k: 'MISSILE', K_l: 'P_BULLET', K_i: ' NUCLEAR'}
HERO_PLANE_QTY = 5
PACKAGE_LIST = [None, 'P_BULLET', 'DEFENCE', 'NUCLEAR']
PACKAGES = {
'P_BULLET': {'IMAGE': 'bulletBox.png', 'QUANTITY': 1000, 'X_SPD': 5, 'Y_SPD': 10, 'SP_FACTOR': 0.5, 'LAYER': 50},
'DEFENCE': {'IMAGE': 'healthBox.png', 'QUANTITY': 1000, 'X_SPD': 5, 'Y_SPD': 10, 'SP_FACTOR': 0.5, 'LAYER': 50},
'NUCLEAR': {'IMAGE': 'nuclearBox.png', 'QUANTITY': 1, 'X_SPD': 5, 'Y_SPD': 10, 'SP_FACTOR': 0.5, 'LAYER': 50}}
有了配置文件,我们来做一个子弹类。直接上代码:
class Bullet(Sprite):
def __init__(self, bulletType, position, layerGroup, bGroup):
self.type = bulletType
self._layer = BULLETS[self.type]['LAYER']
self.groups = layerGroup, bGroup
super().__init__(self.groups)
self.image = pygame.image.load(IMAGE_PATH + BULLETS[self.type]['IMAGE']).convert_alpha()
self.rect = Rect(position, self.image.get_size())
self.destroyValue = BULLETS[self.type]['DESTROY_VALUE']
self.speed = BULLETS[self.type]['SPEED']
self.speedupFactor = BULLETS[self.type]['SP_FACTOR']
self.lastTick = 0
# 目前 子弹 和 导弹都是从发射点开始直线运行,可以考虑将 英雄 的导弹 改为制导模式
def update(self, *args):
tick = args[0]
if tick < self.lastTick:
return
self.lastTick = tick
self.rect.top += self.speed * self.speedupFactor
# 处理飞出游戏界面的子弹(包含敌我双方子弹)
# GAME_AREA_START_HEIGHT 高度用于未来显示游戏状态相关信息。
if self.rect.top >= SCREEN_SIZE[1] or self.rect.bottom <= GAME_AREA_START_HEIGHT:
self.kill()
Bullet类的初始化第一部分定义了自己所在的groups,一个是 Layer groups,用于显示和更新位置时使用,一个是 功能组。子弹类是通用的,适用英雄战机发射,也适用敌机发射。子弹的类型、子弹造型、子弹的速度等通过配置文件来增删改。
子弹速度目前只提供Y轴的,如果想使用制导导弹(需要添加X 速度,并引入相关的math包,以及使用pygame的transform功能调整导弹的角度等) 有兴趣的朋友可以自行探索。
子弹的基本属性就是破环力,加速因子未来可以用于设置难度。
子弹的唯一方法就是update(),用于更新自己的位置,以及出界后自毁。
好了第一部分就到这里。下一部分我将给出英雄战机和敌机类以及相关方法。