在开始介绍之前,首先要确定飞机大战所需的图片以及所需的工具包和工具类,我所使用的图片是下载自别人分享的百度网盘,在代码的最后我会把图片资源和代码链接放上去,还有我们使用pygame提供的模块和random的模块,来进行设计。
代码中我们设计一个sprite.py的python工具类,以plane_main.py为python的主函数类,这样开发将会很简洁,也更加容易开发,有一点很重要的,我们使用精灵组来显示敌机、英雄、子弹和背景图片,也就是说,显示全部都调用精灵组的图片,这样我们就不用一个一个去显示,非常方便。
spirit.py 主要是定义需要的精灵,用于更新显示和碰撞检测。在sprite中导入pygame模块和random模块,在定义我们所需要的全局变量和自定义类,再在自定义类里面编写我们所需要的函数,如下图所示
1. 确定好我们所需要的类后,我们可以一步一步来定义我们所需的类,我们先定义一个GameSprites类作为游戏精灵类,用于游戏的运行
class GameSprites(pygame.sprite.Sprite):
def __init__(self, image_name, speed = 1):
# 调用父类的初始化方法
super().__init__()
# 定义对象属性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
# 图片向下移动
self.rect.y += self.speed
2. 接着我们定义Background游戏背景类,使用两张相同的图片进行循环,一张在y轴正坐标,一张在y轴负坐标。当在正坐标的图片出屏幕时,即self.rect.y >= SCREEN_RECT.height时,让它减去自己的高度,在负坐标那里继续增大,从而实现图片的更替显示。
class Background(GameSprites):
"""
游戏背景精灵
"""
def __init__(self, is_alt=False):
# 调用父类方法,实现精灵和精灵组的创建(image/rect/speed)
super().__init__("./images/img_bg_level_1.jpg")
# 判断是否是交替图像
if is_alt:
self.rect.y = -self.rect.height
def update(self):
# 调用父类的方法实现
super().update()
# 判断是否移出屏幕
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
3. 接着,我们写一个敌机类,用于显示敌机,使用随机函数random先指定敌机的位置,再设定不同的3种速度,这样敌机就可以在图片上随机出现,以不同速度运动了,在敌机飞出屏幕后销毁敌机精灵,防止内存消耗,如下代码所示
class Enemy(GameSprites):
"""敌机精灵"""
def __init__(self):
# 调用父类的初始化
super().__init__("./images/a2-1.png")
# 指定敌机的初始随机速度
self.speed = random.randint(1, 3)
# 指定敌机的初始随机位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self):
# 调用父类方法
super().update()
# 判断敌机是否飞出屏幕,是则从精灵组中删除
if self.rect.y >= SCREEN_RECT.height:
# print("敌机飞出了屏幕")
self.kill()
def __del__(self):
# print("敌机挂了")
pass
4. 定义完敌机类,我们在定义英雄飞机类,这部分代码稍微复杂些,因为要定义开火这个函数,包括英雄和子弹两个精灵组,需要调用子弹精灵组,和敌机精灵组一样,需要定义初始位置,不同的是,英雄可以使用按键进行左右移动,并且可以发射子弹,如下代码所示
class Hero(GameSprites):
def __init__(self):
# 调用父类方法
super().__init__("./images/me1.png", 0)
# 设置英雄初始位置
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 120
# 创建子弹精灵组
self.bullets = pygame.sprite.Group()
def update(self):
# 英雄在水平移动
self.rect.x += self.speed
# 控制英雄不能离开屏幕
if self.rect.x < 0:
self.rec .x = 0
elif self.rect.x > SCREEN_RECT.right:
self.rect.x = SCREEN_RECT.right
def fire(self):
print("发射子弹事件")
for i in (0, 1, 2):
# 创建子弹精灵
bullet = Bullet()
# 设置子弹精灵组的位置
bullet.rect.bottom = self.rect.y - i*20
bullet.rect.centerx = self.rect.centerx
# 将精灵添加到精灵组
self.bullets.add(bullet)
5. 现在编写子弹精灵组的类,子弹主要就一个任务,那就是向上运动,其它的都不用做,相对其它的精灵组要简单。
class Bullet(GameSprites):
"""子弹精灵"""
def __init__(self):
# 调用父类方法
super().__init__("./images/p-f02.png", -2)
def update(self):
# 调用父类方法
super().update()
if self.rect.bottom < 0:
self.kill()
def __del__(self):
# print("子弹被销毁")
pass
到这里,我们所需的精灵组基本已经定义完了,可以开始在主函数中调用,主函数,相对而言就比较简单了,基本上只负责调用和刷新帧率,plane_main.py如下图所示,
主要由七个函数组成,分别是初始化函数、创建精灵函数、开始游戏函数、事件触发中断函数、确认碰撞函数、更新精灵函数和游戏结束函数。
1. 初始化函数如下所示,基本上是固定的,
def __init__(self):
print("游戏初始化")
# 1.创建游戏窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2.创建游戏时钟
self.clock = pygame.time.Clock()
# 3.调用私有方法,精灵和精灵组创建
self.creat_sprites()
# 4. 设置定时器事件,创建敌机
pygame.time.set_timer(CREAT_ENEMY_EVENT, 1000)
# 5. 设置定时器事件,创建子弹
pygame.time.set_timer(HERO_FIRE_EVENT, 500)
2. 创建精灵组,用于更新显示到屏幕
def creat_sprites(self):
# 创建背景精灵
bg1 = Background()
bg2 = Background(True)
# bg2.rect.y = -bg2.rect.height
self.back_ground = pygame.sprite.Group(bg1, bg2)
# 创建敌机精灵组
self.enemy_ground = pygame.sprite.Group()
# 创建英雄和英雄精灵组
self.hero = Hero()
self.hero_ground =pygame.sprite.Group(self.hero)
3. 开始游戏,这个也是固定的,
def start_game(self):
print("游戏开始")
while True:
# 1设置刷新帧率
self.clock.tick(FRAME_PER_SEC)
# 2设置监听
self.__event_handler()
# 3.设置碰撞检测
self.__check_collid()
# 4.更新精灵组
self.__update_sprites()
# 5.更新显示
pygame.display.update()
4. 触发中断检测事件,监测是否按下退出键、敌机是否出现、是否按下左右移动的按键和发射子弹事件,如果检测到有事件发生,记录事件并进行判断为什么事件,再执行相应的代码。这里要注意,使用键盘函数来读取键值
def __event_handler(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
PlaneGame.__game_over()
elif event.type == CREAT_ENEMY_EVENT:
# print("敌机出现")
# 创建敌机精灵,
enemy = Enemy()
# 将敌机精灵添加到精灵组
self.enemy_ground.add(enemy)
elif event.type ==HERO_FIRE_EVENT:
self.hero.fire()
# elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
# print("向右移动")
# 使用键盘提供的方法
key_pressed = pygame.key.get_pressed()
# 判断元组中的键值
if key_pressed[pygame.K_RIGHT]:
self.hero.speed = 2
elif key_pressed[pygame.K_LEFT]:
self.hero.speed = -2
else:
self.hero.speed = 0
5. 检测碰撞函数,这里主要是子弹撞毁敌机,和敌机撞毁英雄,我们只要使用pygame自带的精灵组碰撞检测函数就行了groupcollide和spritecollide,会自动帮我们销毁敌机,但是英雄牺牲就需要判断一下,才能执行,要不然敌机会销毁而英雄不会牺牲。
def __check_collid(self):
# 销毁敌机(两个精灵组碰撞检测)
pygame.sprite.groupcollide(self.hero.bullets, self.enemy_ground, True, True)
# 敌机撞毁英雄
enemies = pygame.sprite.spritecollide(self.hero, self.enemy_ground, True)
if len(enemies) > 0:
# 让英雄牺牲
self.hero.kill()
# 结束游戏
PlaneGame.__game_over()
6. 更新精灵组函数,这个也是固定的两个函数,相应的精灵组使用update和draw函数就行了
def __update_sprites(self):
self.back_ground.update()
self.back_ground.draw(self.screen)
self.enemy_ground.update()
self.enemy_ground.draw(self.screen)
self.hero_ground.update()
self.hero_ground.draw(self.screen)
self.hero.bullets.update()
self.hero.bullets.draw(self.screen)
7. 最后别忘了定义游戏结束的静态函数
@staticmethod
def __game_over():
print("游戏结束")
pygame.quit()
exit()
最后我们定义主函数
if __name__ == '__main__':
# 创建游戏对象
game = PlaneGame()
# 游戏启动
game.start_game()
这样就大功告成了,一个简单的飞机大战就完成了