在开始介绍之前,首先要确定飞机大战所需的图片以及所需的工具包和工具类,我所使用的图片是下载自别人分享的百度网盘,在代码的最后我会把图片资源和代码链接放上去,还有我们使用pygame提供的模块和random的模块,来进行设计。
代码中我们设计一个sprite.py的python工具类,以plane_main.py为python的主函数类,这样开发将会很简洁,也更加容易开发,有一点很重要的,我们使用精灵组来显示敌机、英雄、子弹和背景图片,也就是说,显示全部都调用精灵组的图片,这样我们就不用一个一个去显示,非常方便。
spirit.py 主要是定义需要的精灵,用于更新显示和碰撞检测。在sprite中导入pygame模块和random模块,在定义我们所需要的全局变量和自定义类,再在自定义类里面编写我们所需要的函数,如下图所示

Python飞机大作战课设报告_Group

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如下图所示,

Python飞机大作战课设报告_Python飞机大作战课设报告_02

主要由七个函数组成,分别是初始化函数、创建精灵函数、开始游戏函数、事件触发中断函数、确认碰撞函数、更新精灵函数和游戏结束函数。
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()

这样就大功告成了,一个简单的飞机大战就完成了