上一篇(Python游戏之Pygame——太空飞机大战(三))完成了英雄战机和星空,那么基本上飞机大战的主要元素都已经完成,该是总结成功玩自己游戏的时候了。
哦,差点忘了,Bullet类对于普通子弹和导弹发射来说是通用的,但是对于核弹,发射核弹部分当然也是相同的,但核弹爆炸的效果图以及杀伤情况就完全不同了。下面先给出展示核弹爆炸的方法:
# 处理核弹爆炸,由于核弹爆炸属于特殊事件,放在类里处理不合OOP理念。当然也可以单独为核弹做一个类,不放在 Bullet 类中
def nuclear_explosiing(targetSurf, sound):
for nuclear in nuclearGroup:
if nuclear.rect.top < 500:
nuclear.image = pygame.image.load(IMAGE_PATH + "nuclear_explosing.png").convert_alpha()
for i in range(10):
nuclear.image = pygame.transform.smoothscale(nuclear.image, (110 + 150 * i, 110 + 150 * i))
nuclear.rect = Rect((0, 0), nuclear.image.get_size())
nuclear.rect.center = (SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] // 3)
targetSurf.blit(nuclear.image, nuclear.rect)
pygame.display.update()
sound.play()
# 核弹 kill
nuclear.kill()
return True
return False
这里主要使用了pygame的transform功能,如果想让核弹爆的过程炸稍微慢一点,可以在update()后添加一个延时方法就可以了。有兴趣的朋友可以自己试一下。
下面开始主程序了。
def main():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
pygame.display.set_caption("New Space Fighting")
# 播放背景音乐
pygame.mixer.init()
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.load(SOUND_PATH + 'bg.ogg')
pygame.mixer.music.play(-1)
bulletSound = pygame.mixer.Sound(SOUND_PATH + 'shoot_missile.ogg')
bombSound = pygame.mixer.Sound(SOUND_PATH + 'bomb.ogg')
nuclearSound = pygame.mixer.Sound(SOUND_PATH + 'shoot_nuclear.ogg')
failureSound = pygame.mixer.Sound(SOUND_PATH + 'failure.ogg')
screen.fill((0, 0, 0))
# 初始化 星空,英雄战机等
space = Space(screen)
# 所有子弹、敌机、英雄战机、导弹、核弹、package都在这个 layerGroup中,当然他们也在自己的功能Group里。
layerGroup = LayeredUpdates()
# 初始化英雄战机的总数量
heroPlaneQty = HERO_PLANE_QTY
# 先生产一架英雄战机
heroPlane = HeroPlane(random.choice(list(HERO_PLANES.keys())),
(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - 100),
layerGroup, heroPlaneGroup)
heroPlaneGroup.draw(screen)
pygame.display.update()
# 重复按键设置,所有键响应延迟一样
# 游戏过程中根据得分情况改变参数, 得分达到一定级别 降低延迟,就提高了速度---------------------------
pygame.key.set_repeat(30, 40)
# 控制update()的频率
fpsClock = pygame.time.Clock()
# 用于控制Space中Star的数量和速度等
spaceClock = pygame.time.Clock()
while heroPlaneQty:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
# SPACE KEYDOWN 飞机变形,KEYUP 恢复
heroPlane.transform(event)
key_pressed = pygame.key.get_pressed()
# a,s,w,d 控制英雄战机的飞行
heroPlane.move(key_pressed)
# i,j,k,l 分别发射核弹,普通子弹,导弹,强力子弹
heroPlane.shoot(key_pressed, (bulletSound, nuclearSound))
# 根据核弹位置是否引爆核弹。这里将nuclear_explosiing()放在公共函数文件中了。
if gf.nuclear_explosiing(screen, nuclearSound):
# 核爆过后,整个世界安静了
for sp in enemyPlaneGroup:
sp.kill()
for sp in enemyBulletGroup:
sp.kill()
for sp in heroBulletGroup:
sp.kill()
# 间隔 一段时候后增加敌机,可以通过这个改变生产敌机的速度和每次生产敌机的数量。
if pygame.time.get_ticks() % 20 <= 1:
EnemyPlane(random.choice(list(ENEMY_PLANES.keys())), layerGroup, enemyPlaneGroup)
# 敌我子弹碰撞互相消灭
pygame.sprite.groupcollide(enemyBulletGroup, heroBulletGroup, True, True)
# 击中敌机后使用杀伤力和防御力计算是否消失
for enemyPlane in enemyPlaneGroup:
enemyPlane.was_shot(heroBulletGroup, bombSound)
# 英雄战机捡到包裹
for package in packageGroup:
if pygame.sprite.collide_rect(package, heroPlane):
heroPlane.pickup_package(package.type)
package.kill()
# 处理 heroPlane 被子弹击中 或者被 敌机撞击
if heroPlane.was_collided(enemyBulletGroup) or heroPlane.was_collided(enemyPlaneGroup):
heroPlane.kill()
# 游戏失败
if heroPlaneQty < 1:
failureSound.play()
break
heroPlaneQty -= 1
heroPlane = HeroPlane(random.choice(list(HERO_PLANES.keys())),
(SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - 100),
layerGroup, heroPlaneGroup)
# 更新集群中精灵的位置
tick = pygame.time.get_ticks()
layerGroup.update(tick)
# 刷新背景
screen.fill((0, 0, 0))
# 星空背景
space.showspace(spaceClock)
# 显示集群中所有精灵
layerGroup.draw(screen)
# 刷新屏幕
pygame.display.update()
# 控制帧率
fpsClock.tick(40)
if __name__ == "__main__":
main()
好了,现在基本上可以玩游戏了。当然,还缺少素材还有文件组织。为了方便有兴趣的朋友,我自己做了一点素材,这里提供给给大家。
由于不让添加压缩文件,只好一个一个上了。
简单说一下,头向上的是英雄战机和子弹,向下的是敌机和子弹,还有package(药箱、核弹、强力子弹),核爆效果图等,有兴趣的朋友可以根据配置文件来给图片命名。也可以修改配置文件改为自己喜欢的名字。
都说没有声音,再好的戏也出不来。但是没办法上传声音啊,哀莫能租。但是这难不倒真正有兴趣的朋友。
大家可以从万能的网上找到自己喜欢的音效。
下面是本游戏的文件组织
嗯?怎么这里还有label,button,message,scoreboard啊?在这个系列的第一篇已经说过了,之前单独有一篇关于一文学习pygame之Layer的文章,大家可以看一下。不过这些不是玩游戏必须的,通过这个系列四篇文章的内容,完全可以开始自己的游戏之旅了。当然有兴趣继续探索的朋友可以给游戏添加辅助功能,比如记分、显示剩余战机数量、适当修改程序提供选择那种战机、选择那种子弹组合、剩余多少核弹等等,这些就留给真正感兴趣的朋友吧,动手是最好的学习方法,不是吗?
有兴趣的朋友可以根据自己的理解组织文件结构,然后调试的过程中自己 import相关的包。说明一下,我的环境是 win10 + python3.7 + pycharm。需要引入的包如下:
import pygame
from pygame.sprite import Group
from pygame.sprite import Sprite
from pygame.sprite import LayeredUpdates
from pygame.locals import *
import random
from sys import exit
另外几个全局Group放在setting里面了
enemyBulletGroup = Group() # 敌机发射的子弹组
heroBulletGroup = Group() # 英雄子弹组
enemyPlaneGroup = Group() # 敌机组
heroPlaneGroup = Group() # 英雄组
nuclearGroup = Group() # 核弹组
packageGroup = Group() # 被击落的敌机可能掉出的包
好了,我也是个初学Python的菜鸟,编码的过程难免有些不雅的地方。有些可以改善的地方,比如
1、敌机和英雄战机可以把公共部分组织为一个飞机基类,然后对基类扩展为响应的敌机类和英雄战机类
2、尽可能减小主程序中while 循环体的大小,将相关 fighting过程打包为函数放在公共的 functions.py里面
等等,这些就留给真正有兴趣,想写出更优雅python代码的朋友吧。
有些小的细节,比如事件处理中为什么同时使用了键盘事件的两种方式,需要大家动手玩一玩就会更清楚,比如用了Group,为什么通篇都没有看到 Group的 .add() 和 remove()方法等,精灵怎么进入gourp的?怎么remove的?如果改用 add() 和 remove() 方法,会有什么问题吗?需要实践去探索。
另外,有些参数并不是最佳的,比如键盘响应时间间隔、帧率、敌机生产速度、发射子弹的频率等等,还有相关素材,如果想要更好的效果,需要更好的图片和声音素材,需要对参数进行细调。这些就不在本文的范畴了。
谢谢大家的阅读!