目标
- 设计英雄和子弹类 
- 使用pygame.key.get_pressed()移动英雄 
- 发射子弹 
1.设计英雄和子弹类
1.1英雄需求
- 游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像素 
- 英雄每隔0.5秒发射一次子弹,每次连发三枚子弹 
- 英雄默认不会移动,需要通过左/右方向键,控制英雄在水平方向移动 
 
   1.2子弹需求
- 子弹从英雄的正上方发射沿直线向上方飞行,飞出屏幕后,需要从精灵组中删除 
 
   Hero -- 英雄
- 初始化方法 
- 指定英雄图片 
- 初始速度 = 0 -- 英雄默认静止不动 
- 定义bullets子弹精灵组保存子弹精灵 
- 重写update()方法 
- 英雄需要水平移动 
- 并且需要保证不能移出屏幕 
- 增加bullets属性,记录所有子弹精灵 
- 增加fire方法,用于发射子弹 
Bullet -- 子弹
- 初始化方法 
- 指定子弹图片 
- 初始速度= -2 -- 子弹需要向上方飞行 
- 重写update()方法 
- 判断是否飞出屏幕,如果是,从精灵组删除 
2.创建英雄
2.1准备英雄类
分析
- 在plane_sprites新建Hero类 
- 重写初始化方法,直接指定图片名称,并且将初始速度设置为0 
- 设置英雄的初始位置 
 
   - centerx = x + 0.5 * width 
- centery = y + 0.5 * height 
- bottom = y + height 
 
   代码演示
- 在plane_sprites.py中新建Hero类 
class Hero(GameSprite):
    """英雄精灵"""
    def __init__(self):
        # 1.调用父类方法,设置image&speed
        super().__init__("./images/me1.png", 0)
        # 2.设置英雄的初始位置
        self.rect.centerx = SCREEN_RECT.centerx
        self.rect.bottom = SCREEN_RECT.bottom - 1202.2绘制英雄
分析
- 在__create_sprites,添加英雄精灵和英雄精灵组 
- 后续要针对英雄做碰撞检测以及发射子弹,所以英雄需要单独定义成属性 
- 在__update_sprites,让英雄精灵组调用update和draw方法 
代码演示
- 在plane_main.py中修改__create_sprites方法 
# 创建英雄的精灵和精灵组
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)- 在plane_main.py中修改__update_sprites方法 
self.hero_group.update()
self.hero_group.draw(self.screen)3.移动英雄位置
在pygame中针对键盘按键的捕获,有两种方式
- 第一种方式:判断event.type == pygame.KEYDOWN 
- 第二种方式: 
- 首先使用pygame.key.get_pressed()返回所有按键元组 
- 通过键盘常量,判断元组中某一个键是否被按下 -- 如果被按下,对应数值为1 
请问:这两种方式的区别?
第一种方式
向右移动的按键如果被一直按下,控制台只会输出一个 向右移动,需要松开按键重新按下,飞机才能持续向右移动
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
    print("向右移动...") 
   第二种方式
向右移动的按键如果被一直按下(按下不放),控制台会输出多个 向右移动,按键不需要松开,飞机就可以持续向右移动
# 使用键盘提供的方法获取键盘按键。返回所有按键的元组,如果某个键被按下,对应的值会是1
keys_pressed = pygame.key.get_pressed()
# 判是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
    print("向右移动...") 
   结论
- 第一种方式event.type用户 必须要抬起按键才算一次 按键事件,操作灵活性会大打折扣 
- 第二种方式用户可以按住方向键不放,就能够实现持续向某一个方向移动了,操作灵活性更好 
3.1移动英雄位置
演练步骤
- 在Hero类中重写update方法 
- 用速度speed和英雄rect.x进行叠加 
- 不需要调用父类方法 -- 父类方法只是实现了单纯的垂直运动 
- 在__event_handler方法中根据左右方向键设置英雄的速度 
- 向右 => speed = 2 
- 向左 => speed =-2 
- 其他 => speed = 0 
代码演练
- 在Hero类,重写update()方法,根据速度水平移动英雄的飞机 
- 在plane_sprites.py的Hero类中重写update()方法 
def update(self):
        
    # 英雄在水平方向移动
    self.rect.x += self.speed- 在plane_main.py的__event_handler方法中根据左右方向键设置英雄的速度 
# 使用键盘提供的方法获取键盘按键。返回所有按键的元组,如果某个键被按下,对应的值会是1
keys_pressed = pygame.key.get_pressed()
# 判是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
    self.hero.speed = 2
elif keys_pressed[pygame.K_LEFT]:
    self.hero.speed = -2
else:
    self.hero.speed = 03.2控制英雄运动边界
- 在plane_sprites.py的Hero类的update()方法中判断英雄是否超出屏幕边界 
 
   - right = x + width利用right属性可以非常容易的针对右侧设置精灵位置 
 
   代码演练
- 在plane_sprites.py的Hero类的update()方法中判断英雄是否超出屏幕边界 
def update(self):
    # 英雄在水平方向移动
    self.rect.x += self.speed
    # 控制英雄不能离开屏幕
    if self.rect.x < 0:
        self.rect.x = 0
    elif self.rect.right > SCREEN_RECT.right:
        self.rect.right = SCREEN_RECT.right4.发射子弹
需求回顾 -- 英雄需求
- 游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像素 
- 英雄每隔0.5秒发射一次子弹,每次连发三枚子弹 
- 英雄默认不会移动,需要通过左/右方向键,控制英雄在水平方向移动 
4.1添加发射子弹事件
分析
pygame的定时器使用方法非常固定
- 定义定时器常量 -- eventid 
- 在初始化方法中,调用set_timer方法设置定时器事件 
- 在游戏循环中,监听定时器事件 
代码演练
- 在plane_sprites.py中的Hero类中定义fire方法 
def fire(self):
    print("发射子弹...")- 在plane_sprites.py中的顶部定义英雄发射子弹事件 
# 英雄发射子弹事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1- 在plane_main.py中的PlaneGame类的__init__方法中修改定时器事件 
pygame.time.set_timer(HERO_FIRE_EVENT, 500)- 在plane_main.py中的PlaneGame类的__event_handler方法中让英雄发射子弹 
elif event.type == HERO_FIRE_EVENT:
    self.hero.fire()4.2定义子弹类
需求回顾 -- 子弹需求
- 子弹从英雄的正上方发射沿直线向上方飞行,飞出屏幕后,需要从精灵组中删除 
Bullet -- 子弹
- 初始化方法 
- 指定子弹图片 
- 初始速度= -2 -- 子弹需要向上方飞行 
- 重写update()方法 
- 判断是否飞出屏幕,如果是,从精灵组删除 
定义子弹类
分析
- 在plane_sprites.py新建Bullet继承自GameSprite 
- 重写初始化方法,调用父类方法,直接指定图片名称,并且设置初始速度 
- 重写update()方法,调用父类方法,判断子弹飞出屏幕从精灵组删除 
代码演练
class Bullet(GameSprite):
    """子弹精灵"""
    def __init__(self):
        # 调用父类方法,设置子弹图片,设置初始速度
        super().__init__("./images/bullet1.png", -2)
    def update(self):
        # 调用父类方法,让子弹沿着垂直方向飞行
        super().update()
        # 判断子弹是否飞出屏幕
        if self.rect.bottom < 0:
            self.kill()4.3发射子弹
演练步骤
- 在Hero的初始化方法中创建子弹精灵组属性 
- 修改plane_main.py的__update_sprites方法,让子弹精灵组调用update和draw方法 
- 实现fire()方法 
- 创建子弹精灵 
- 设置初始位置 -- 在英雄的正上方 
- 将子弹添加到精灵组 
代码实现
- 初始化方法 
plane_sprites.py中的Hero类中修改初始化方法
 # 3.创建子弹精灵组
 self.bullets = pygame.sprite.Group()- 修改fire()方法 
plane_sprites.py中的Hero类中修改fire()方法
def fire(self):
    print("发射子弹...")
    # 1.创建子弹精灵
    bullet = Bullet()
    # 2.设置精灵位置,比英雄的y值小20个像素
    bullet.rect.bottom = self.rect.y - 20
    bullet.rect.centerx = self.rect.centerx
    # 3.将精灵添加到精灵组
    self.bullets.add(bullet)一次发射三枚子弹
 
   - 修改fire()方法 
plane_sprites.py中的Hero类中修改fire()方法,利用for循环
def fire(self):
    print("发射子弹...")
    for i in (0, 1, 2):
        # 1.创建子弹精灵
        bullet = Bullet()
        # 2.设置精灵位置,比英雄的y值小20个像素
        bullet.rect.bottom = self.rect.y - i * 20
        bullet.rect.centerx = self.rect.centerx
        # 3.将精灵添加到精灵组
        self.bullets.add(bullet)内容总结于:https://space.bilibili.com/37974444



















