• 【Pygame 学习笔记】8.精灵


    术语“精灵”是旧计算机和游戏机的保留。这些较旧的盒子无法以足够快的速度绘制和擦除普通图形,使其无法用作游戏。这些机器有特殊的硬件来处理需要快速动画的游戏对象。这些对象被称为“精灵”并有特殊的限制,但可以非常快速地绘制和更新。它们通常存在于视频中的特殊覆盖缓冲区中。这些天来,计算机已经变得足够快,可以在没有专用硬件的情况下处理类似精灵的对象。sprite 一词仍然用于表示 2D 游戏中的任何动画。

    这一篇学习笔记,我们来学习精灵,首先给出基础框架代码

    1. import pygame
    2. from pygame.locals import *
    3. import sys
    4. class Game:
    5. def __init__(self):
    6. pygame.init()
    7. self.W,self.H=800,800
    8. self.screen=pygame.display.set_mode((self.W,self.H))
    9. pygame.display.set_caption("【Pygame 学习笔记】")
    10. def listen(self):
    11. for event in pygame.event.get():
    12. if event.type==QUIT:
    13. sys.exit()
    14. def draw(self):
    15. self.screen.fill((255,255,255))
    16. def run(self):
    17. while True:
    18. self.listen()
    19. self.draw()
    20. pygame.display.update()
    21. if __name__ == '__main__':
    22. game=Game()
    23. game.run()

     给出需要的资源文件:

    balloon.png


    我们来写一个源源不断有气球从屏幕顶端往下落的程序,首先,我们将balloon.png放置于python文件同目录下的resources文件夹,resources文件夹可以用来储存资源文件,然后定义一个类Balloon,继承自pygame.sprite.Sprite,初始化中进行超类初始化

    1. class Balloon(pygame.sprite.Sprite):
    2. def __init__(self):
    3. super().__init__()

    然后继续在初始化方法中创建self.image变量用于储存气球的图片,将图片导入并缩小到50x50的大小,self.rect变量储存该精灵的位置,self.speed表示下落的速度,在程序开头导入random,import random as rd,然后使用随机库的生成随机整数方法,随机生成x坐标,底部y坐标为窗口顶部

    注意,这里的self.image和self.rect变量名不可以改成其它名字,因为这两个变量是在pygame的Sprite类中定义的,我们只是重写为自己想要的内容,并且在之后我们要讲到的将精灵绘制到窗口的操作都和这两个变量息息相关,所以这里的self.image和self.rect存储的必须是图像和它对应的rect对象

    1. self.image=pygame.transform.smoothscale(pygame.image.load("resources/balloon.png"),(50,50))
    2. self.rect=self.image.get_rect()
    3. self.rect.midbottom=rd.randint(50,game.W-50),0
    4. self.speed=1

    然后,重写update方法,这里的update方法也是不能改名的哦,在update方法中,让y坐标递增,然后只要rect的顶部到达窗口最下方,就清除该精灵,清楚精灵用Sprite中自带的kill方法

    1. def update(self):
    2. self.rect.y+=self.speed
    3. if self.rect.top>=game.H:
    4. self.kill()

    这样,一个简简单单的精灵类就写完啦,接下来,我们来学习如何将精灵绘制到屏幕中,还有如何添加精灵等操作

    在Game类初始化中创建精灵组,用pygame.sprite.Group类

            self.balloons=pygame.sprite.Group()

    然后在主程序中定义CREATEBALLOON,值为USEREVENT+1

    CREATEBALLOON=USEREVENT+1

    USEREVENT是pygame留给用户使用的事件常量,大于USEREVENT的值都是供用户使用的,所以我们这里把他定义为USEREVENT+1

    然后再Game类中run程序的while循环前写入

    pygame.time.set_timer(CREATEBALLOON,700)

    上面这行代码用到了pygame.time.set_timer方法,传入两个参数,第一个是事件,第二个是毫秒数,表示从这行代码开始,每运行多少毫秒触发一次事件,我们这里设置为700,也就是每700毫秒触发一次创建气球的事件,接下来我们在listen中进行事件的监听,在for循环事件遍历中添加这段代码,当程序捕捉到这个事件时,就向self.balloons精灵组添加精灵,用到了add方法,传入的参数就是我们精灵类的一个实例化

    1. if event.type==CREATEBALLOON:
    2. self.balloons.add(Balloon())

    然后,在draw方法中,对精灵组进行更新,然后绘制,更新用到了update方法,绘制用draw方法,draw传入窗口的Surface,也就是直接传入self.screen即可

    1. self.balloons.update()
    2. self.balloons.draw(self.screen)

    最终代码如下:

    1. import pygame
    2. from pygame.locals import *
    3. import sys
    4. import random as rd
    5. CREATEBALLOON=USEREVENT+1
    6. class Game:
    7. def __init__(self):
    8. pygame.init()
    9. self.W,self.H=800,800
    10. self.screen=pygame.display.set_mode((self.W,self.H))
    11. pygame.display.set_caption("【Pygame 学习笔记】")
    12. self.balloons=pygame.sprite.Group()
    13. def listen(self):
    14. for event in pygame.event.get():
    15. if event.type==QUIT:
    16. sys.exit()
    17. if event.type==CREATEBALLOON:
    18. self.balloons.add(Balloon())
    19. def draw(self):
    20. self.screen.fill((255,255,255))
    21. self.balloons.update()
    22. self.balloons.draw(self.screen)
    23. def run(self):
    24. pygame.time.set_timer(CREATEBALLOON,700)
    25. while True:
    26. self.listen()
    27. self.draw()
    28. pygame.display.update()
    29. class Balloon(pygame.sprite.Sprite):
    30. def __init__(self):
    31. super().__init__()
    32. self.image=pygame.transform.smoothscale(pygame.image.load("resources/balloon.png"),(50,50))
    33. self.rect=self.image.get_rect()
    34. self.rect.midbottom=rd.randint(50,game.W-50),0
    35. self.speed=1
    36. def update(self):
    37. self.rect.y+=self.speed
    38. if self.rect.top>=game.H:
    39. self.kill()
    40. if __name__ == '__main__':
    41. game=Game()
    42. game.run()

    我们现在运行代码,发现气球下落的速度过快,在Balloon中修改speed为0.1,我们发现,精灵创建出来后,只会一直停留在窗口顶部,这是因为,精灵的rect和普通的rect稍有不同,精灵的rect对象参数值一般都为整数,我们将其增减小数都是无效的,也就是说精灵的下落每次都要下落1个像素,我们来讲解一下解决方案

    解决方法1:修改运行速度

    因为我们的运行速度过快,每秒run中while循环了很多次,我们要适当减少次数,并不难,在run的while前创建clock

            clock=pygame.time.Clock()

    用下面方法看看帧率

    1. clock.tick()
    2. print(clock.get_fps())

    因为我的这台电脑配置比较好,比较流畅,所以控制台输出的帧率一直在5000和3333.333之间跳动

    我们在tick中添加一个参数,将帧率改为120

    1. clock.tick(120)
    2. print(clock.get_fps())

    再运行程序,可看到,气球就正常地缓缓下落了,控制台输出的帧率,也是非常的接近120

     调试完毕,再把print语句删掉即可,最终代码如下

    1. import pygame
    2. from pygame.locals import *
    3. import sys
    4. import random as rd
    5. CREATEBALLOON=USEREVENT+1
    6. class Game:
    7. def __init__(self):
    8. pygame.init()
    9. self.W,self.H=800,800
    10. self.screen=pygame.display.set_mode((self.W,self.H))
    11. pygame.display.set_caption("【Pygame 学习笔记】")
    12. self.balloons=pygame.sprite.Group()
    13. def listen(self):
    14. for event in pygame.event.get():
    15. if event.type==QUIT:
    16. sys.exit()
    17. if event.type==CREATEBALLOON:
    18. self.balloons.add(Balloon())
    19. def draw(self):
    20. self.screen.fill((255,255,255))
    21. self.balloons.update()
    22. self.balloons.draw(self.screen)
    23. def run(self):
    24. pygame.time.set_timer(CREATEBALLOON,700)
    25. clock=pygame.time.Clock()
    26. while True:
    27. clock.tick(120)
    28. self.listen()
    29. self.draw()
    30. pygame.display.update()
    31. class Balloon(pygame.sprite.Sprite):
    32. def __init__(self):
    33. super().__init__()
    34. self.image=pygame.transform.smoothscale(pygame.image.load("resources/balloon.png"),(50,50))
    35. self.rect=self.image.get_rect()
    36. self.rect.midbottom=rd.randint(50,game.W-50),0
    37. self.speed=1
    38. def update(self):
    39. self.rect.y+=self.speed
    40. if self.rect.top>=game.H:
    41. self.kill()
    42. if __name__ == '__main__':
    43. game=Game()
    44. game.run()

    解决方法2

    我们可以自己在精灵类中添加一个变量和一个计数器,每次运行update就将计数器+1,到达变量设置的值的时候,计数器归零,然后精灵才进行下落操作。将精灵类改成这样

    1. class Balloon(pygame.sprite.Sprite):
    2. def __init__(self):
    3. super().__init__()
    4. self.image=pygame.transform.smoothscale(pygame.image.load("resources/balloon.png"),(50,50))
    5. self.rect=self.image.get_rect()
    6. self.rect.midbottom=rd.randint(50,game.W-50),0
    7. self.speed=1
    8. self.toUpdate=20
    9. self.counter=0
    10. def update(self):
    11. self.counter+=1
    12. if self.counter>=self.toUpdate:
    13. self.counter=0
    14. self.rect.y+=self.speed
    15. if self.rect.top>=game.H:
    16. self.kill()

    我们再运行程序,气球也成功地减缓下落速度了

    解决方法3:每次主循环运行一次过后进行手动延迟操作

    这种方法也不难,一行代码就能搞定,用pygame.time.delay方法,传入一个数字,表示延迟毫秒数,直接将下面这行代码添加到while循环的最后面即可(我们这里设置为自己感觉适合的大小就可以,我这里设置为10毫秒)

                pygame.time.delay(10)

    最终代码如下:

    1. import pygame
    2. from pygame.locals import *
    3. import sys
    4. import random as rd
    5. CREATEBALLOON=USEREVENT+1
    6. class Game:
    7. def __init__(self):
    8. pygame.init()
    9. self.W,self.H=800,800
    10. self.screen=pygame.display.set_mode((self.W,self.H))
    11. pygame.display.set_caption("【Pygame 学习笔记】")
    12. self.balloons=pygame.sprite.Group()
    13. def listen(self):
    14. for event in pygame.event.get():
    15. if event.type==QUIT:
    16. sys.exit()
    17. if event.type==CREATEBALLOON:
    18. self.balloons.add(Balloon())
    19. def draw(self):
    20. self.screen.fill((255,255,255))
    21. self.balloons.update()
    22. self.balloons.draw(self.screen)
    23. def run(self):
    24. pygame.time.set_timer(CREATEBALLOON,700)
    25. while True:
    26. self.listen()
    27. self.draw()
    28. pygame.display.update()
    29. pygame.time.delay(10)
    30. class Balloon(pygame.sprite.Sprite):
    31. def __init__(self):
    32. super().__init__()
    33. self.image=pygame.transform.smoothscale(pygame.image.load("resources/balloon.png"),(50,50))
    34. self.rect=self.image.get_rect()
    35. self.rect.midbottom=rd.randint(50,game.W-50),0
    36. self.speed=1
    37. def update(self):
    38. self.rect.y+=self.speed
    39. if self.rect.top>=game.H:
    40. self.kill()
    41. if __name__ == '__main__':
    42. game=Game()
    43. game.run()

    今天的【Pygame 学习笔记】就讲到这里,喜欢我的文章别忘了多多点赞收藏+关注支持一下博主哦!

    谢谢大家的支持~

  • 相关阅读:
    JSP第一篇 -----JSP九大内置对象(隐式对象)和四大域对象
    一起Talk Android吧(第三百四十四回: JSON概述)
    支持向量机(SVM)----sklearn库的应用
    基于jeecgboot流程管理平台的在线表单设计修改成formdesigner(一)
    计算机CV方向-顶级会议和期刊
    Pb从入坑到放弃(三)数据窗口
    【笔者感悟】笔者的学习感悟【三】
    l8-d10 TCP协议是如何实现可靠传输的
    上采样,下采样,卷积,反卷积,池化,反池化,双线性插值【基本概念分析】
    less 用法
  • 原文地址:https://blog.csdn.net/leleprogrammer/article/details/125872048