Pygame飞机大战(二)——用动画精灵创建一组飞机,并检测碰撞

本文详细讲解了在游戏开发中如何使用Pygame的动画精灵(Sprite)模块创建动态对象,包括创建自定义动画精灵类、实现移动与边界检测,并通过组(Group)管理多个动画精灵,以及如何实现碰撞检测,确保游戏中的飞机不会重叠。

我们首先来讲一下动画精灵是个什么东西?
我们在之前显示图片时候,都是先把背景色填充,然后再把飞机绘制在屏幕上,最后刷新窗体,这中间就有一个擦除和绘制的过程;我们现在来想象一下,在游戏的时候会有很多的飞机,随着我们现在的机器配置越来越高当然没什么问题,可以很快速的处理很多图片的显示和消失,但是以前的硬件基础并不是很好,这些游戏机就有一些特殊的硬件,专门用来处理需要快速移动的游戏对象,这些对象就称为“动画精灵”。简单的来说,动画精灵就是一次性显示的一组像素,它返回的是一种图形对象,将多个图形作为一个整体显示。

那么,我们需要怎么实现呢?
pygame的sprite模块提供了一个动画精灵的基类——Sprite,一般来讲我们不会直接使用基类,而是基于基类来创建自己的子类使用,接下来我们看一下他是怎么使用的;先来创建一个自己的子类吧:

class PlaneClass(pygame.sprite.Sprite):            # 我们基于动画精灵的基类来创建子类
    def __init__(self,img,position,speed):         # 初始化,一般来讲将需要用到的属性在这里进行初始化操作
        pygame.sprite.Sprite.__init__(self)        # 初始化动画精灵
        self.image = pygame.image.load(img)        # 加载飞机图片
        self.rect = self.image.get_rect()          # 获取图片的rect
        self.rect.left,self.rect.top = position    # 设置图片的初始位置
        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]

这里来讲一下什么是基类,什么是子类?
基类就是父类,这就好比一个父亲一个儿子,儿子肯定继承了父亲的一部分基因,所以外貌、性格等会与父亲相似,但是儿子毕竟是一个单独的个体,首先属性参数会不一样,其次可能会有其他的属性是父亲所没有的;基类和子类也是一样的道理,我们创建一个类,相当于创建了一个模型,继承了父类的所有属性,但是子类也可以添加自己的属性和方法,当我们这个类创建完毕之后,就可以用这个类创建对象了,这个对象就具有了这个类的所有属性和方法了。

以上面的代码来说,创建了一个PlaneClass类,继承了pygame.sprire.Sprite的属性,我们在初始话的时候,self就代表它本身所具有的属性,然后将参数设置上去;在下面move就是我们自己定义的方法,这个就是基类所不具备的,就像父亲不会英语,儿子会一样;

airplanes = []        # 创建列表,用来存放创建的飞机

for i in range(4):
    img_position = [i*100,10]                  # 设置飞机的初始位置
    speed = [choice([-2,2]),choice([-2,2])]    # 让他们的速度都随机
    airplane = PlaneClass('./images/me1.png',img_position,speed)    # 基于类创建飞机
    airplanes.append(airplane)    # 将飞机放到列表中

clock = pygame.time.Clock()    # 创建一个clock对象,用来控制游戏每秒的帧数

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

    screen.fill(bg)
    for each in airplanes:    # 遍历类,将每个飞机都显示出来
        each.move()           # 移动并检测边界
        screen.blit(each.image,each.rect)    # 将飞机绘制到界面上
    pygame.display.flip()     # 刷新游戏界面
    clock.tick(60)    # 设置游戏每秒60帧


好了,我们现在已经知道怎么用动画精灵创建一组飞机了,我们会发现飞机在移动的时候会产生重叠,当然友方飞机问题不大,但是是敌方飞机,或者我们想要他们产生一个碰撞效果,该怎么处理呢?

imgs = ['./images/me1.png','./images/enemy1.png','./images/enemy2.png']
group = pygame.sprite.Group()    # 创建一个组,之前我们是创建一个列表,然后把生成的飞机添加到列表里面的 ,现在我们存放在这个组里面

for i in range(3):
    img_position = [i*200,10]
    speed = [choice([-2,2]),choice([-2,2])]
    airplane = PlaneClass(imgs[i],img_position,speed)
    group.add(airplane)    # 其余的,没有太大的变化,就是添加到组

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)    # 最后绘制飞机到界面上

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

    screen.fill(bg)
    collide_check(group)    # 调用方法,将组内的飞机移动、检测并显示
    pygame.display.flip()
    clock.tick(60)

这里需要说的是几个方法的使用:

  1. pygame.sprite.Group.add()方法添加动画精灵到组当中;
  2. pygame.sprite.Group.remove()方法从组当中移除某一个动画精灵;
  3. pygame.sprite.spritecollide()方法用来检测某个动画精灵组中的动画精灵是否发生碰撞;
  4. pygame.sprite.collide_mask是pygame提供的一个图像蒙版模块,用来返回图像的轮廓,为什么需要这个呢?我们可以将上面代码中pygame.sprite.spritecollide()的第四个参数删掉,会发现飞机并没有发生完全重叠就发生碰撞了,这是因为默认碰撞检测的是图像的矩形部分,矩形部分产生重叠,就认为发生了碰撞,这样显然是有问题的,所以我们需要将其轮廓显示出来,然后再进行判断;

完整代码如下:

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

class PlaneClass(pygame.sprite.Sprite):
    def __init__(self,img,position,speed):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(img)
        self.rect = self.image.get_rect()
        self.rect.left,self.rect.top = position
        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]

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.init()
screen_size = width,height = 480,700
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption('飞机大战')
bg = (0,255,0)

imgs = ['./images/me1.png','./images/enemy1.png','./images/enemy2.png']
group = pygame.sprite.Group()

for i in range(3):
    img_position = [i*200,10]
    speed = [choice([-2,2]),choice([-2,2])]
    airplane = PlaneClass(imgs[i],img_position,speed)
    group.add(airplane)

clock = pygame.time.Clock()

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

    screen.fill(bg)
    collide_check(group)
    pygame.display.flip()
    clock.tick(60)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值