编程语言
首页 > 编程语言> > python学习笔记第十二天------------飞机大战项目(一)

python学习笔记第十二天------------飞机大战项目(一)

作者:互联网

飞机大战项目(一)

  • 1. pygame 快速入门
  • 2. 敌机出场
  • 3.碰撞检测


  • 1. pygame 快速入门

    1.1 使用 pygame 创建图形窗口

    1.1.1 游戏的初始化和退出

    方法 说明
    pygame.init() 导入并初始化所有 pygame 模块,使用其他模块之前,必须先调用 init 方法
    pygame.quit() 卸载所有 pygame 模块,在游戏结束之前调用!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZS82jSU-1580111990941)(media/15025046487919/001_pygame%E7%9A%84init%E5%92%8Cquit.png)]

    import pygame
    
    pygame.init()
    
    # 游戏代码...
    
    pygame.quit()
    
    

    1.1.2 理解游戏中的坐标系

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5o9nms3d-1580111990942)(media/15025046487919/002_%E6%B8%B8%E6%88%8F%E7%AA%97%E5%8F%A3%E5%92%8C%E5%9D%90%E6%A0%87%E7%B3%BB.png)]

    Rect(x, y, width, height) -> Rect
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0wmkdbh0-1580111990943)(media/15025046487919/003_pygame.Rect.png)]

    提示

    案例演练

    需求

    1. 定义 hero_rect 矩形描述 英雄的位置和大小
    2. 输出英雄的 坐标原点xy
    3. 输出英雄的 尺寸宽度高度
    hero_rect = pygame.Rect(100, 500, 120, 126)
    
    print("坐标原点 %d %d" % (hero_rect.x, hero_rect.y))
    print("英雄大小 %d %d" % (hero_rect.width, hero_rect.height))
    # size 属性会返回矩形区域的 (宽, 高) 元组
    print("英雄大小 %d %d" % hero_rect.size)
    

    1.1.3 创建游戏主窗口

    方法 说明
    pygame.display.set_mode() 初始化游戏显示窗口
    pygame.display.update() 刷新屏幕内容显示,稍后使用

    set_mode 方法

    set_mode(resolution=(0,0), flags=0, depth=0) -> Surface
    
    # 创建游戏主窗口
    screen = pygame.display.set_mode((480, 700))
    

    1.1.4 简单的游戏循环

    # 创建游戏主窗口
    screen = pygame.display.set_mode((480, 700))
    
    # 游戏循环
    while True:
        pass
    

    1.2 理解 图像 并实现图像绘制

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CLx6LXS9-1580111990944)(media/15025046487919/004_%E5%8A%A0%E8%BD%BD%E5%92%8C%E6%98%BE%E7%A4%BA%E5%9B%BE%E5%83%8F.png)]

    提示:要想在屏幕上看到绘制的结果,就一定要调用 pygame.display.update() 方法

    代码演练 I —— 绘制背景图像

    需求

    1. 加载 background.png 创建背景
    2. 背景 绘制在屏幕的 (0, 0) 位置
    3. 调用屏幕更新显示背景图像
    # 绘制背景图像
    # 1> 加载图像
    bg = pygame.image.load("./images/background.png")
    
    # 2> 绘制在屏幕
    screen.blit(bg, (0, 0))
    
    # 3> 更新显示
    pygame.display.update()
    

    代码演练 II —— 绘制英雄图像

    需求

    1. 加载 me1.png 创建英雄飞机
    2. 英雄飞机 绘制在屏幕的 (200, 500) 位置
    3. 调用屏幕更新显示飞机图像
    # 1> 加载图像
    hero = pygame.image.load("./images/me1.png")
    
    # 2> 绘制在屏幕
    screen.blit(hero, (200, 500))
    
    # 3> 更新显示
    pygame.display.update()
    

    透明图像

    理解 update() 方法的作用

    可以在 screen 对象完成 所有 blit 方法之后,统一调用一次 display.update 方法,同样可以在屏幕上 看到最终的绘制结果

    案例调整

    # 绘制背景图像
    # 1> 加载图像
    bg = pygame.image.load("./images/background.png")
    
    # 2> 绘制在屏幕
    screen.blit(bg, (0, 0))
    
    # 绘制英雄图像
    # 1> 加载图像
    hero = pygame.image.load("./images/me1.png")
    
    # 2> 绘制在屏幕
    screen.blit(hero, (200, 500))
    
    # 3> 更新显示 - update 方法会把之前所有绘制的结果,一次性更新到屏幕窗口上
    pygame.display.update()
    

    1.3 理解 游戏循环游戏时钟

    现在 英雄飞机 已经被绘制到屏幕上了,怎么能够让飞机移动呢

    1.3.1 游戏中的动画实现原理

    1.3.2 游戏循环

    游戏的两个组成部分

    游戏循环的开始 就意味着 游戏的正式开始

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-heNVVNpQ-1580111990947)(media/15025046487919/005_%E6%B8%B8%E6%88%8F%E4%B8%BB%E6%A8%A1%E5%9D%97.png)]

    游戏循环的作用

    1. 保证游戏 不会直接退出
    2. 变化图像位置 —— 动画效果
      • 每隔 1 / 60 秒 移动一下所有图像的位置
      • 调用 pygame.display.update() 更新屏幕显示
    3. 检测用户交互 —— 按键、鼠标等…

    1.3.3 游戏时钟

    # 3. 创建游戏时钟对象
    clock = pygame.time.Clock()
    i = 0
    
    # 游戏循环
    while True:
    
        # 设置屏幕刷新帧率
        clock.tick(60)
    
        print(i)
        i += 1
    

    1.3.4 英雄的简单动画实现

    需求

    1. 游戏初始化 定义一个 pygame.Rect 的变量记录英雄的初始位置
    2. 游戏循环 中每次让 英雄y - 1 —— 向上移动
    3. y <= 0 将英雄移动到屏幕的底部

    提示:

    • 每一次调用 update() 方法之前,需要把 所有的游戏图像都重新绘制一遍
    • 而且应该 最先 重新绘制 背景图像
    # 4. 定义英雄的初始位置
    hero_rect = pygame.Rect(150, 500, 102, 126)
    
    while True:
    
        # 可以指定循环体内部的代码执行的频率
        clock.tick(60)
    
        # 更新英雄位置
        hero_rect.y -= 1
    
        # 如果移出屏幕,则将英雄的顶部移动到屏幕底部
        if hero_rect.y <= 0:
            hero_rect.y = 700
    
        # 绘制背景图片
        screen.blit(bg, (0, 0))
        # 绘制英雄图像
        screen.blit(hero, hero_rect)
    
        # 更新显示
        pygame.display.update()
    

    作业

    1. 英雄向上飞行,当 英雄完全从上方飞出屏幕后
    2. 将飞机移动到屏幕的底部
    if hero_rect.y + hero_rect.height <= 0:
        hero_rect.y = 700
    

    提示

    if hero_rect.bottom <= 0:
        hero_rect.y = 700
    

    1.3.5 在游戏循环中 监听 事件

    事件 event

    监听

    只有 捕获 到用户具体的操作,才能有针对性的做出响应

    代码实现

    # 游戏循环
    while True:
    
        # 设置屏幕刷新帧率
        clock.tick(60)
    
        # 事件监听
        for event in pygame.event.get():
    
            # 判断用户是否点击了关闭按钮
            if event.type == pygame.QUIT:
                print("退出游戏...")
    
                pygame.quit()
    
                # 直接退出系统
                exit()
    

    1.4 理解 精灵精灵组

    1.4.1 精灵 和 精灵组

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6fzp5Re4-1580111990948)(media/15025046487919/006_pygame.Sprite.png)]

    精灵

    精灵组

    Group(*sprites) -> Group
    

    注意:仍然需要调用 pygame.display.update() 才能在屏幕看到最终结果

    1.4.2 派生精灵子类

    1. 新建 plane_sprites.py 文件
    2. 定义 GameSprite 继承自 pygame.sprite.Sprite

    注意

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNdqKvQ3-1580111990949)(media/15025046487919/007_GameSprite.png)]

    属性

    方法

    提示

    import pygame
    
    
    class GameSprite(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, *args):
            
            # 默认在垂直方向移动
            self.rect.y += self.speed
            
    

    1.4.3 使用 游戏精灵 和 精灵组 创建敌机

    需求

    步骤

    1. 使用 from 导入 plane_sprites 模块
      • from 导入的模块可以 直接使用
      • import 导入的模块需要通过 模块名. 来使用
    2. 游戏初始化 创建 精灵对象精灵组对象
    3. 游戏循环中精灵组 分别调用 update()draw(screen) 方法

    职责

    实现步骤

    from plane_sprites import *
    
    # 创建敌机精灵和精灵组
    enemy1 = GameSprite("./images/enemy1.png")
    enemy2 = GameSprite("./images/enemy1.png", 2)
    enemy2.rect.x = 200
    enemy_group = pygame.sprite.Group(enemy1, enemy2)
    
    # 让敌机组调用 update 和 draw 方法
    enemy_group.update()
    enemy_group.draw(screen)
    
    # 更新屏幕显示
    pygame.display.update()
    

    2. 敌机出场

    # 敌机出场

    2.1 使用定时器添加敌机

    运行 备课代码观察 敌机的 出现规律

    1. 游戏启动后,每隔 1 秒出现一架敌机
    2. 每架敌机 向屏幕下方飞行,飞行 速度各不相同
    3. 每架敌机出现的 水平位置 也不尽相同
    4. 当敌机 从屏幕下方飞出,不会再飞回到屏幕中

    2.1.1 定时器

    set_timer(eventid, milliseconds) -> None
    

    定时器事件的监听

    2.1.2 定义并监听创建敌机的定时器事件

    pygame定时器 使用套路非常固定:

    1. 定义 定时器常量 —— eventid
    2. 初始化方法 中,调用 set_timer 方法 设置定时器事件
    3. 游戏循环 中,监听定时器事件

    1) 定义事件

    # 敌机的定时器事件常量
    CREATE_ENEMY_EVENT = pygame.USEREVENT
    
    # 4. 设置定时器事件 - 每秒创建一架敌机
    pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)
    

    2) 监听定时器事件

    def __event_handler(self):
        
        for event in pygame.event.get():
        
            # 判断是否退出游戏
            if event.type == pygame.QUIT:
                PlaneGame.__game_over()
            elif event.type == CREATE_ENEMY_EVENT:
                print("敌机出场...")
    

    2.2 设计 Enemy

    1. 游戏启动后,每隔 1 秒出现一架敌机
    2. 每架敌机 向屏幕下方飞行,飞行 速度各不相同
    3. 每架敌机出现的 水平位置 也不尽相同
    4. 当敌机 从屏幕下方飞出,不会再飞回到屏幕中

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iKIoORDj-1580112033421)(media/15025309517247/014_%E6%B4%BE%E7%94%9FEnemy%E5%AD%90%E7%B1%BB.png)]

    2.2.1 敌机类的准备

    class Enemy(GameSprite):
        """敌机精灵"""
        
        def __init__(self):
            
            # 1. 调用父类方法,创建敌机精灵,并且指定敌机的图像
            super().__init__("./images/enemy1.png")
    
            # 2. 设置敌机的随机初始速度
    
            # 3. 设置敌机的随机初始位置
        
        def update(self):
            
            # 1. 调用父类方法,让敌机在垂直方向运动
            super().update()
            
            # 2. 判断是否飞出屏幕,如果是,需要将敌机从精灵组删除
            if self.rect.y >= SCREEN_RECT.height:
                print("敌机飞出屏幕...")    
    

    2.3 创建敌机

    演练步骤

    1. __create_sprites,添加 敌机精灵组
      • 敌机是 定时被创建的,因此在初始化方法中,不需要创建敌机
    2. __event_handler,创建敌机,并且 添加到精灵组
      • 调用 精灵组add 方法可以 向精灵组添加精灵
    3. __update_sprites,让 敌机精灵组 调用 updatedraw 方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1AYEKnk-1580112033421)(media/15025309517247/006_pygame.SpriteII.png)]

    演练代码

    # 敌机组
    self.enemy_group = pygame.sprite.Group()
    
    self.enemy_group.update()
    self.enemy_group.draw(self.screen)
    
    elif event.type == CREATE_ENEMY_EVENT:
        self.enemy_group.add(Enemy())
    

    2.4 随机敌机位置和速度

    1) 导入模块

    1. 官方标准模块导入
    2. 第三方模块导入
    3. 应用程序模块导入
    
    import random
    

    2) 随机位置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZjbU5KS-1580112033422)(media/15025309517247/015_%E9%A3%9E%E6%9C%BA%E5%88%9D%E5%A7%8B%E4%BD%8D%E7%BD%AE.png)]

    使用 pygame.Rect 提供的 bottom 属性,在指定敌机初始位置时,会比较方便

    3) 代码实现

    def __init__(self):
    
        # 1. 调用父类方法,创建敌机精灵,并且指定敌机的图像
        super().__init__("./images/enemy1.png")
    
        # 2. 设置敌机的随机初始速度 1 ~ 3
        self.speed = random.randint(1, 3)
    
        # 3. 设置敌机的随机初始位置
        self.rect.bottom = 0
        
        max_x = SCREEN_RECT.width - self.rect.width
        self.rect.x = random.randint(0, max_x)
    

    2.5 移出屏幕销毁敌机

    检测敌机被销毁

    def __del__(self):
        print("敌机挂了 %s" % self.rect)
    

    代码实现

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iS355SbY-1580112033423)(media/15025309517247/006_pygame.SpriteII.png)]

    def update(self):
        super().update()
        
        # 判断敌机是否移出屏幕
        if self.rect.y >= SCREEN_RECT.height:
            # 将精灵从所有组中删除
            self.kill()
    

    3.碰撞检测

    3.1 了解碰撞检测方法

    pygame.sprite.groupcollide()

    groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
    

    pygame.sprite.spritecollide()

    spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
    

    3.2 碰撞实现

    def __check_collide(self):
    
        # 1. 子弹摧毁敌机
        pygame.sprite.groupcollide(self.hero.bullets, self.enemy_group, True, True)
        
        # 2. 敌机撞毁英雄
        enemies = pygame.sprite.spritecollide(self.hero, self.enemy_group, True)
        
        # 判断列表时候有内容
        if len(enemies) > 0:
        
            # 让英雄牺牲
            self.hero.kill()
            
            # 结束游戏
            PlaneGame.__game_over()
    
    曾鸿举 发布了19 篇原创文章 · 获赞 24 · 访问量 3048 私信 关注

    标签:第十二天,游戏,python,精灵,笔记,pygame,屏幕,敌机,rect
    来源: https://blog.csdn.net/zenghongju/article/details/104088252