python中的pygame游戏模块入门(二)

动画精灵

动画精灵表示作为一个单位来移动和显示一组像素,它是一种图形对象。我们
可以把动画精灵想成一个小图片-----可以在屏幕上移动的图形对象,并且可以与其他
图形对象交互。

  • 图像(image):为动画精灵显示的图片;
  • 矩形区(rect):包含动画精灵的的矩形区域。

Pygame的sprite模块提供了一个动画精灵基类,名为Sprite。一般,我们不会直接使用基类,而是基于
pygame.sprite.Sprite来创建自己的子类。

下面,我们来完成一个例子,基于pygame.sprite.Sprite基类来创建我们的子类 ,命名为PlaneClass。

import sys
import pygame
from pygame.locals import *
#创建动画精灵的子类,命名为PlaneClass
class PlaneClass(pygame.sprite.Sprite):
    def __init__(self, img_file, location):
        pygame.sprite.Sprite.__init__(self) #初始化动画精灵
        self.image = pygame.image.load(img_file) #加载图像
        self.rect = self.image.get_rect() #获取图像的矩形数据
        self.rect.left, self.rect.top = location #设置图像的初始位置

实例化PlaneClass

pygame.init()
screen_size = 480, 700
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption(“AirplaneSprite”)
background = pygame.image.load(“background.png”).convert()
screen.blit(background, (0, 0)) #只加载一次图片,因此先将背景加载好
img_airplane = "me1.png"
airplanes = []
for i in range(3):
    location_img = [i *100, 10] #每次循环产生一个不同的位置
    airplane = PlaneClass(img_airplane, location_img) #在这个位置创建一个airplane实例对象
    airplanes.append(airplane) #把新创建的airplane添加到列表
#依次将airplane显示在窗口不同的位置
for each in airplanes:
    screen.blit(each.image, each.rect)

程序退出

running = True
while running:
   for event in pygame.event.get():
      if event.type == QUIT:
          pygame.quit()
          sys.exit()
   pygame.display.flip()

现在我们加载了多个动画精灵,怎样让动画精灵动起来呢?我们要给它们增加一个移动的技能,给PlaneClass类添加speed属性和move()方法。

class PlaneClass(pygame.sprite.Sprite):
   def __init__(self, img_file, location, speed): #增加speed参数
       pygame.sprite.Sprite.__init__(self)
       self.image = pygame.image.load(img_file)
       self.rect = self.image.get_rect()
       self.rect.left, self.rect.top = location
       self.speed = speed #为PlaneClass类创建一个speed属性
       #定义move()方法来移动精灵
   def move(self):
       self.rect = self.rect.move(self.speed)
       #如果遇到边界,则移动速度反向
       if self.rect.left < 0 or self.rect.right > width:
          self.speed[0] = -self.speed[0]
       if self.rect.top < 0 or self.rect.bottom > height:
          self.speed[1] = -self.speed[1]

动起来…

from random import *
……[省略代码]
screen_size = width, height = 480, 700
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("AirplaneSprite")
background = pygame.image.load("background.png").convert()

img_airplane = "me1.png"
airplanes = []
speed = [2, 2] #初始化speed
for i in range(3):
    location_img = [i *100, 10]
    speed = [choice([-2, 2]), choice([-2, 2])] #随机生成速度
    airplane = PlaneClass(img_airplane, location_img, speed) #实例化对象
    airplanes.append(airplane)

调用move()方法移动精灵

running = True
while running:
   for event in pygame.event.get():
      if event.type == QUIT:
         pygame.quit()
         sys.exit()
   pygame.time.delay(10)
   screen.blit(background, (0, 0))
   for each in airplanes:
       each.move() #调用move()方法,移动精灵
       screen.blit(each.image, each.rect)
   pygame.display.flip()

尝试在同一个程序中加载不同的精灵

……[省略代码]
#定义所有精灵的文件列表
imgs = [“me1.png”, “enemy1.png”, “enemy2.png”, “enemy3_n1.png”]
airplanes = []
speed = [2, 2] #初始化speed
for i in range(4):
   location_img = [i *100, 10]
   speed = [choice([-2, 2]), choice([-2, 2])] #随机生成速度
   airplane = PlaneClass(imgs[i], location_img, speed) #加载所有的飞机对象
   airplanes.append(airplane)
碰撞检测

碰撞检测指的是检测两个动画精灵接触或者重叠。

  • pygame提供了一种方法对动画精灵分组。例如,在保龄球游戏中,所有的瓶在
    一组,球在另一组。组与碰撞检测密切相关,我们可以检测球何时击倒某个瓶子,
    因此需要寻找精灵(球)与球瓶组中所有精灵之间的碰撞;当然,还可以检测组内
    部的碰撞(比如球瓶相互碰倒)。

碰撞检测分为两种:

  • 某一动画精灵与自己所在组的动画精灵之间的碰撞;
  • 某一动画精灵与其他组的动画精灵之间的碰撞;

那么怎么分组呢?Pygame提供了pygame.sprite.Group类,用来管理分组过个sprite对象。比如我们经常使用pygame.sprite.Group.add()方法添加动画精灵到组当中,使用pygame.sprite.Group.remove()方法从组当中移除某一个动画精灵。

pygame.sprite.spritecollide()方法用来检测某个动画精灵组当中的“精灵们”是否与其他的动画精灵碰撞。spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
#动画精灵,精灵们#是否要移除组中所有的精灵?True or False
#什么样的方式碰撞,默认为矩形碰撞

下面,我们完成一个小游戏,加载几个小飞机,互相碰撞以后 ,反向移动。
首先,定义PlaneClass,与上节课程序类似。

import sys
import pygame
from pygame.locals import *
from random import *

class PlaneClass(pygame.sprite.Sprite):
	def __init__(self, img_file, location, speed):
		pygame.sprite.Sprite.__init__(self)
		self.image = pygame.image.load(img_file)
		self.rect = self.image.get_rect()
		self.rect.left, self.rect.top = location
		self.speed = speed
	def move(self):
		self.rect = self.rect.move(self.speed)
		if self.rect.left < 0 or self.rect.right > width:
		self.speed[0] = -self.speed[0]
		if self.rect.top < 0 or self.rect.bottom > height:
		self.speed[1] = -self.speed[1]

定义一个函数collide_check()用来检测小飞机之间是否产生碰撞。

def collide_check(group):   #传入参数group为小飞机动画精灵的组
    #先移动所有的小飞机
    for plane in group:
        plane.move()
    #分别检测每一个小飞机是否与其他小飞机碰撞
    for plane in group:
         group.remove(plane) #第一步,从组中删除该精灵(小飞机)
 			 #第二步,调用spritecollide()方法检测该精灵是否与组中其他精灵碰撞
         if pygame.sprite.spritecollide(plane, group, False):
            #如果产生碰撞,则该精灵的运动方向反向
              plane.speed[0] = -plane.speed[0]
              plane.speed[1] = -plane.speed[1]
         group.add(plane) #第三步,再将该精灵加入组
         screen.blit(plane.image, plane.rect)

主程序中,创建精灵组,并且将所有的精灵添加到组中。

pygame.init()
screen_size = width, height = 480, 700
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption(“AirplaneSprite”)
background = pygame.image.load(“background.png”).convert()

imgs = [“me1.png”, “enemy1.png”, “enemy2.png”]
img_file = “me1.png”
group = pygame.sprite.Group()   #创建精灵组
speed = [2, 2]
for i in range(3):
    location_img = [i *120, 10]
    speed = [choice([-2, 2]), choice([-2, 2])]
	airplane = PlaneClass(imgs[i], location_img, speed)
	group.add(airplane)     #将各个精灵添加到组中
clock = pygame.time.Clock()

主程序中调用动画精灵碰撞检测的函数

running = True
while running:
  for event in pygame.event.get():
     if event.type == QUIT:
         pygame.quit()
         sys.exit()
  screen.blit(background, (0, 0))
  collide_check(group) #调用collide_check()函数,检测并更新精灵的位置
  pygame.display.flip()
  clock.tick(30)

程序完成,但是,有一个问题,小飞机并不是完全碰撞,而是碰撞到了小飞机图像的矩形边(如下图),就认为碰撞了。总觉得不太理想,该怎样让小飞机看上去真的碰撞呢?

pygame提供了一个图像蒙版的模块pygame.mask,用来实现完美检测,该模块中Pygame.mask.from_surface()方法可以通过制定的图像返回一个蒙版(图像轮廓)。

我们我们使用spritecollide(sprite, group, dokill, collided = None) 方法检测碰撞时,只传入了前三个参数,现在我们就要用到第四个参数了,我们在第四个参数传入pygame.sprite.collide_mask
(实际是调用pygame.sprite.collide_mask ()方法),即实现蒙版检测碰撞,只有两个动画精灵的轮廓发生碰撞时,才被认为是碰撞,即完美碰撞。

除了使用蒙版外,还可以使用圆形范围检测。

修改部分代码,实现完美碰撞。

class PlaneClass(pygame.sprite.Sprite):
    def __init__(self, img_file, location, speed):
       pygame.sprite.Sprite.__init__(self)
       self.image = pygame.image.load(img_file)
       self.rect = self.image.get_rect()
       self.rect.left, self.rect.top = location
       self.speed = speed
       self.mask = pygame.mask.from_surface(self.image)  #获取图像的蒙版
def collide_check(group):
    for plane in group:
       plane.move()
    for plane in group:
       group.remove(plane)
       #使用图像的蒙版进行检测,从而实现完美碰撞检测
       if pygame.sprite.spritecollide(plane, group, False, pygame.sprite.collide_mask):
          plane.speed[0] = -plane.speed[0]
          plane.speed[1] = -plane.speed[1]
       group.add(plane)
       screen.blit(plane.image, plane.rect)

播放声音

为了让作品更好玩,更有趣,游戏和其他很多程序都添加了声音(音乐),下面我们学习如何在程序中播放音乐或音效等声音

  • pygame中有一个处理声音的模块,即pygam.mixer。该模块提供了一些方法来播放,暂停,停止声音
  • 我们可以播放的声音或音乐的文件格式 有以下几种:war格式,mp3格式,wma格式,ogg格式

要播放一段声音,必须初始化pygame.mixer,如下:

pygame.mixer.init()

然后准备播放的声音,我们先试试比较短的声音,这样的声音通常保存为wav文件,对于这种类型的文件,pygame.mixer会使用一个Sound对象,如下:

voice=pygame.mixer.Sound("get_bomb.wav")
voice.play()

另一种大量使用的声音是音乐,音乐大多数以mp3、wma或ogg文件存储,而且文件较大,声音时间较长,要播放这些音乐,pygame会使用mixer中的music模块,如下:

pygame.mixer.music,load("game_music.ogg")
pygame.mixer.music.play

我们写一个小程序,测试一下这两种方法吧。

import sys
import pygame
from pygame.locals import *

pygame.init()
pygame.mixer.init()
screen_size = width, height = 320, 480
pygame.display.set_mode(screen_size)
pygame.display.set_caption(“testVoice”)
#加载wav文件格式的声音并播放
voice = pygame.mixer.Sound("get_bomb.wav")
voice.play()
#加载ogg文件格式的声音并播放
#pygame.mixer.music.load("game_music.ogg")
#pygame.mixer.music.play()  

running = True
while running:
  for event in pygame.event.get():
    if event.type == QUIT:
       sys.exit()
       pygame.quit()
  pygame.display.flip()

为上节课的游戏程序添加背景音乐,背景音乐文件名为”game_music.ogg”。

pygame.init()
#初始化pygame.mixer
pygame.mixer.init()
screen_size = width, height = 480, 700
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("AirplaneSprite")
background = pygame.image.load("background.png").convert()
#加载背景音乐文件”game_music.ogg”
pygame.mixer.music.load("game_music.ogg")
#播放音乐
pygame.mixer.music.play()

当两个小飞机碰撞时,播放碰撞的声音,声音文件为”get_bomb.wav”。

def collide_check(group):
   for plane in group:
       plane.move()
   for plane in group:
       group.remove(plane)
       if pygame.sprite.spritecollide(plane, group, False, pygame.sprite.collide_mask):
          plane.speed[0] = -plane.speed[0]
          plane.speed[1] = -plane.speed[1]
          #加载声音文件
          collide_voice = pygame.mixer.Sound("get_bomb.wav")
          #播放声音
          collide_voice.play()
       group.add(plane)
       screen.blit(plane.image, plane.rect)

声音有点大?怎样调节音量呢?

  • pygame.mixer.music.set_volume()方法可以调节音乐的音量大小;
  • 如果加载的是声音,我们可以使用声音对象的set_volume()方法调节音量,比如本节第一个程序中voice.set_volume(0.2);
  • 括号中传入的参数为从0到1的小数,0.5表示最大音量的50%
……[省略代码]
pygame.mixer.music.load(“game_music.ogg”)
pygame.mixer.music.set_volume(0.2)   #调节音量
pygame.mixer.music.play()
……[省略代码]
collide_voice = pygame.mixer.Sound("get_bomb.wav")
collide_voice.set_volume(0.2)    #调节音量
collide_voice.play()

按下键盘上/下方向键调节背景音乐的音量大小。

#定义调节音量大小的变量
volumeNum = 1.0
……[省略代码]
running = True
while running:
  for event in pygame.event.get():
     if event.type == QUIT:
        pygame.quit()
        sys.exit()
        #通过上/下方向键调节背景音乐音量的大小
     if event.type == KEYDOWN:
        if event.key == K_UP and volumeNum < 1:
           volumeNum += 0.1
        if event.key == K_DOWN and volumeNum > 0:
           volumeNum -= 0.1
        pygame.mixer.music.set_volume(volumeNum)
  screen.blit(background, (0, 0))
  collide_check(group)
  pygame.display.flip()
  clock.tick(30)

我们发现背景音乐播放一段时间后,就播放结束,不再继续播放。该怎样让音乐重复播放呢?
我们可以在调用play()方法时,在括号内传入一个特殊值 -1,这样音乐就会永远重复下去,如下:

pygame.mixer.music.play(-1)

如果传入其他数值,可以让音乐播放一定的次数,比如 3,可以让音乐重复播放3次。

pygame.mixer.music.play(3)

试着添加更多的音乐。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值