1.1游戏中实现背景的滚动

1)创建两张背景图像精灵

  • 第一张完全与屏幕重合
  • 第二张在屏幕的正上方
    2)两张图像一起向下方运动
  • self.rect.y += self.speed
    3)当任意背景精灵的self.rect.y >= 屏幕的高度说明已经移动到屏幕的下方
    4)将移动到屏幕下方的这张图像设置到屏幕上方
  • rect.y = -rect.height

1.2背景设计

  • 初始化方法
    。直接指定背景图片
    。is_alt判断是否是另一张图像
    • False表示第一张图像,需要与屏幕重合
    • True表示另一张图像,在屏幕的正上方
  • update()方法
    。 判断是否移出屏幕,如果是,将图像设置到屏幕的正上方,从而实现交替滚动
    继承如果父类提供的方法不能满足子类的需求:
  • 派生一个子类
  • 在子类中针对特有的需求,重写父类方法,并进行扩展

02.显示游戏背景

2.1背景精灵的基本实现

  • 在plane_sprites 新建 Background 继承自 GameSprite

      class Background(GameSprite):   
    

      “””游戏背景精灵”””

      def updape(self):

         # 1.调用父类的方法实现
         super().update()

         # 2. 判断是否移出屏幕,如果移出将图像设置到屏幕的上方
         if self.rect.y >= SCEEN_RECT.heidht:
           self.rect.y = -self.rect.height

###2.2 在plane_main.py中显示背景精灵
1.在 __create_sprites方法中创建精灵和精灵组
2.在 __update_sprites方法中,让精灵组调用 update()和 draw()方法
__create_sprites 方法

def __creat_sprite(self):  

    # 创建背景精灵和精灵组
    bg1 = Background("./文件目录/文件名)
    bg2 = Background("./文件目录/文件名)
    bg2.rect.y = -bg2.rect.height

    self.back_group = pygame.sprite.Group(bg1, bg2)

__update _ sprites 方法

def __update_sprites(self):

    self.back_group.update()
    self.back_group.draw(self.screen)

敌机出场

  • 使用定时器添加敌机
  • 设计 Enemy类

##01.使用定时器添加敌机

####1.1定时器

  • 在pygame 中可以使用 pygame.time.set_tiner() 来添加定时器

  • 所谓定时器,就是每隔一段时间,去执行一些操作
    set_timer(eventid, milliseconds) => None

  • set_timer可以创建一个事件

  • 可以在游戏循环的事件监听方法中捕获到该事件

  • 第一个参数事件代号需要基于常量 pygame.USEREVBNT来指定
    。USEREVBNT 是一个整数,再增加的事件可以使用 USEREVENT + 1指定,依次类推…

  • 第二个参数是事件触发间隔的毫秒值

定时器事件的监听

  • 通过 pygame.event.get()可以获取当前时刻所有的事件列表
  • 遍历列表并且判断event.type 是否等于 eventid,如果相等,表示定时器事件发生

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

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

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

1)定义事件

  • 在plane_ sprites.py的顶部定义事件常量
    #敌机出现事件
    CREATE_ BNEMY_EVENT = pygame.USEREVBNT

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

  • 初始化方法
    。指定敌机團片
    。随机敌机的初始位置和初始速度
    ●写update()方法
    。判断是否飞出屏幕,如果是,从精灵组删除
    2.1敌机类的准备

####2.2创建敌机
演练步骤
1.在_ create_ sprites,添加敌机精灵组

  • 敌机是定时被创建的,因此在初始化方法中,不需要创建敌机
    2.在_ event_ handler, 创建敌机,并且添加到精灵组
    ●调用精灵组的add方法可以向精灵组添加精灵
    3.在_ update_ sprites,让敌机精灵组调用update 和draw方法

精灵(需要派生子类)
inage记录医像数据
rect记录在屏幕上的位置
update(*args):更新精灵位置
kill():从所有组中删除

精灵组
__ init__(self,* 精灵):
add(* sprites): 向络中增加精灵
spritesl:返图所有精灵列表
update(*args):让组中所有精灵用update方法
draw(Surface): 将绝中所有精灵的inage,绘制到Surface的rect位置

####2.3随机敌机位和速度
1)导入模块
.在导入模块时,建议按照以下顺序导入
1.官方标准模块导入
2.第三方模块导入
3.应用程序模块导入

.修改plane, sprites.py增加randon 的导入
Import randon

2)随机位置

3)代码实现

  • 修改初始化方法随机敌机出现速度和位置

    def __ init__ (self):

     #1.调用父类方法创建敌机精灵,并且指定我机的图像  
     super().__ init__ ("./图片位置/图片名")
    
     #2.设置战机的陈机初始速度1 ~ 3  
     self.speed = randon.randint(1, 3)
    
     #3.设置战机的创机权始位置  
     self.rect.botton = 0
    
     max_x = SCREEN_RECT.width-self.rect.width
     self.rect.x = randon.randint(0, max_x)
    

####2.4移出屏幕销毁敌机

  • 敌机移出屏幕之后,如果没有撞到英雄,敌机的历史使命已经终结
  • 需要从敌机组删除,否则造成内存浪费

检测敌机被销毁

  • __ del__ 内置方法会在对象被销毁前调用,在开发中,可用于判断对象是否被销毁

    def del(self):
    print(“敌机挂了 %s” % self.rect)

  • 判断敌机是否飞出屏幕,如果是,调用kill()方法从所有组中删除

    def update(self):
    super().update(args)

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

##英雄登场

##01.设计英雄和子弹类

####英雄需求
1.游戏启动后英雄会出现在屏幕的水平中间位置,距离屏幕底部120像素
2.英雄每隔0.5秒发射一次子弹,每次连发三枚
3.英雄默认不会移动,需要通过左右方向键,控制英雄水平移动方向

####子弹需求
1.子弹从英雄的正上方发射沿直线向上方飞行
2.飞出屏幕后需要从精灵组中删除

####Hero——英雄
●初始化方法
。指定英雄图片
。初始速度=0–英雄默认静止不动
。定义bullets 子弹精灵组保存子弹精灵
●重写update0方法
。英雄需要水平移动
。并且需要保证不能移出屏幕
●增加bullets 属性,记录所有子弹精灵
●增加fire方法,用于发射子弹

##02.创建英雄
####2.1准备英雄类

  • 在plane_sprites新建Hero类
  • 重写初始化方法,直接指定图片名称,并且将初始速度设置为0
  • 设置英雄的初始位置

| pyga.Rect |
| x,y |
| left,top,bottom,right,|
| size,width,height |

  • centerx = x + 0.5* width

  • centery = y + 0.5* width

  • bottom = y + height

    class Hero(GameSprite):
    “””英雄精灵”””

    def init(self):

    # 1.调用父类方法,设置image&speed
    super().init(“./战机1.jpg”, 0)
    # 2.设置英雄的初始位置
    self.rect.centerx = SCREEN_RECT.centerx
    self.rect.bottom = SCREEN_RECT.bottom - 120

####2.2绘制英雄
1.在__ create_sprites,添加精灵英雄和英雄精灵组

  • 后续要针对英雄做碰撞检测以及子弹发射
  • 所以英雄需要单独定义成属性
    2.在_ update_ sprites,让英雄精灵组调用update和draw方法

代码实现
●修改__ create_ sprites方法如下:

self.hero_group.update()
self.hero_group.draw(self.screen)

##03.移动英雄位置
在 pygame中针对按键的捕获有两种方式

  • 第一种方式判断 event.type == pygame.KEYDOWN
  • 第二种方式
    1.首先使用pygame.key.get()返回按键元组
    2.通过按键常量,判断元组中某一个键是否被按下——如果被按下,对应值为1

●第一种方式(一按一动)

elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
    print("向右移动…")

●第二种方式(可按住不放)

#返回所有按键的元组,如果某个键被按下,对应的值会是1
kwys_pressed = pygame.key.get_pressed()
#判断是否按下了方向键
if keys_pressed[pygame.K_RIGHT]:
    print("向右移动…") 

注:
●第一种方式 event.type 用户必须抬起按键才算一次 按键事件,操作灵活度大打折扣
●第二种方式用户可以按住方向按键不放,就能够实现持续向某一个方向移动了,操作灵活性更好

###3.1移动英雄位置
演练步骤
1.在Hero类中重写update方法
●用速度speed和英雄rect.x进行叠加
●不需要调用父类方法–父类方法只是实现了单纯的垂直运动
2.在gevent_handter方法中根据左右方向键设置英雄的速度

●向右=> speed=2
●向左=> speed=-2
●其他=> speed=0

代码演练
●在Hero类,写update()方法,根据速度水平移动英雄的飞机

def update(self):
   # 英雄在水平方向的移动
   self.rect.x += self.speed

●在__ event_ handler中添加移动方向

 keys_pressed = pygame.key.get_pressed()
    # 判断元组中对应的按键索引值 1
    if keys_pressed[pygame.K_RIGHT]:
        self.hero.speed = 1
    elif keys_pressed[pygame.K_LEFT]:
        self.hero.speed = -1
    else:
        self.hero.speed = 0

###3.2控制英雄运动边界

  • 在Hero类的update()方法判断英雄是否超出屏幕边界
    | pygame.Rect |
    | x,y |
    | left,top,bottom,right, |
    | center,cernterx,centery |
    | size,width,height|

  • right = x + width 利用right属性可以非常容易的针对右侧设置精灵位置

##04.发射子弹

1.游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像
2.英雄每隔0.5秒发射次子弹,每次连发三枚子弹
3.英雄默认不会移动,需要通过左右方向键,控制英雄在水平方向移动

###4.1添加发射子弹事件
pygane的定时器使用套路手常固定:
1.义定时器常量–eventid
2.在初始化方法中,调用set _tiner方法设定时器事件
3.在游戏循环中,监听定时器事件
代码实现
●在Hero中定义fire方法

def fire(self):
   print("发射子弹...)

###4.2定义子弹类

子弹需求
1.子弹从英雄的正上方发射沿直线向上方飞行
2.飞础屏幕后,需要从精灵组中删除

Bullt –子弹
●初始化方法
。指定子弹图片
。初始速度=-2–子弹需要向上方飞行
●重写update()方法
。判断是否飞出屏幕如果是,从精灵组删除

定义子弹类
●在plane sprites 新建Bullet 继承自GaneSprite
●重写初始化方法,直接指定图片名称并且设置初始速度
●写updatel)方法判断子弹飞础屏幕从精灵组删除

class Bullet(GameSprite):
"""子弹精灵"""

    def __init__(self):

        # 调用父类的方法,设置子弹图片,设置初始速度
        super().__init__("./子弹的图片", -2)

    def update(self):

        # 调用父方法,让子弹研垂直方向飞行
        super().update()

        # 判断子弹是否飞出屏幕,如果是从精灵组删除
        if self.rect.bottom < 0:
            self.kill()

###4.3发射子弹
演练步骤
1.在Hero的初始化方法中创建子弹精灵组属性
2.修改plane. mainpy的_ update sprites方法让子弹精灵组调用update和draw 方法
3.实现fire()方法
●创建子弹精灵
●设置初始位置–在英雄的正上方
●将子弹添加到精灵组
代码实现
●初始化方法

# 创建子弹组
self.buttets = pygame.sprite.Group()

●修改fire()方法

def fire(self):
   
    # 1.创建子弹精灵
    bullet = Bullet()

    # 2设置精灵的位置
    bullet.rect.bottom = self.rect.y - 20
    bullet.rect.centerx = self.rect.centerx

    # 3将精灵添加精灵组
    self.bullets.add(bullet)

##碰撞检测
##01.了解碰撞检测方法

  • pygam 提供了两个方便的方法可实现碰撞检测:
    pygam.sprite.groupcpollide()

  • 两个精灵组中所有的精灵碰撞检测

    groupllide(group1,group2,dokill1,dokill2,collide = None) —> Sprite_dic

  • 如果将dokill设置为Ture则发生碰撞的精灵将被自动移除

  • collide参数是用于计算碰撞的回调函数
    。如果没有指定,则每个精灵必须有一个rect属性
    pygame.sprite.spritecollide()
    *判断某个精灵和指定精灵组中的精灵的碰撞

    spritecollide(sprite, group, dokill, collide = None) —> Sprite_list(返回列表)

(dokill英雄飞机与敌机的碰撞检测,为Ture同归于尽,False安然无恙)