Python游戏之Pygame——太空飞机大战(三)

上一篇(Python游戏之Pygame——太空飞机大战(二))完成了敌机类以及敌机坠毁时释放包裹类,这一篇将给出英雄战机类和处理。由于英雄战机是由游戏者操控的,所以要处理操控事件,比如往那个方向飞,发射子弹或者导弹,或者都发射,遇到敌机太多时还可以发射大boss——核弹,遇到很多子弹时通过变形躲子弹等。看起来很炫酷,下面开始打码。

class HeroPlane(Sprite):
    def __init__(self, heroType, position, layerGroup, hPlaneGroup):
        self.groups = layerGroup, hPlaneGroup
        self.type = heroType
        self._layer = HERO_PLANES[self.type]['LAYER']
        super().__init__(self.groups)

        self.image = pygame.image.load(IMAGE_PATH + HERO_PLANES[self.type]['IMAGE']).convert_alpha()
        self.rect = Rect(position, self.image.get_size())

        self.xSpeed = HERO_PLANES[self.type]['X_SPD']
        self.ySpeed = HERO_PLANES[self.type]['Y_SPD']
        self.speedupFactor = HERO_PLANES[self.type]['SP_FACTOR']

        self.bulletType = random.choice(list(HERO_BULLETS_TYPE.values()))
        self.missileType = random.choice(list(HERO_MISSILES_TYPE.values()))
        self.bShootCount = HERO_PLANES[self.type]['B_COUNT']
        self.mShootCount = HERO_PLANES[self.type]['M_COUNT']
        self.nuclearQty = HERO_PLANES[self.type]['QUANTITY']
        self.defence = HERO_PLANES[self.type]['DEFENCE']

        # 捡到power子弹包计算数量
        self.power_bullet_qty = 0

    def move_left(self):
        if self.rect.left >= self.xSpeed * self.speedupFactor:
            self.rect.left -= self.xSpeed * self.speedupFactor
        else:
            self.rect.left = 0

    def move_right(self):
        if self.rect.right <= SCREEN_SIZE[0] - self.xSpeed * self.speedupFactor:
            self.rect.right += self.xSpeed * self.speedupFactor
        else:
            self.rect.right = SCREEN_SIZE[0]

    def move_up(self):
        if self.rect.top >= GAME_AREA_START_HEIGHT + self.ySpeed * self.speedupFactor:
            self.rect.top -= self.ySpeed * self.speedupFactor
        else:
            self.rect.top = GAME_AREA_START_HEIGHT

    def move_down(self):
        if self.rect.bottom <= SCREEN_SIZE[1] - self.ySpeed * self.speedupFactor:
            self.rect.bottom += self.ySpeed * self.speedupFactor
        else:
            self.rect.bottom = SCREEN_SIZE[1]

	# 处理键盘事件,分别用 awsd 来控制方向,你懂得,如果你喜欢 方向键自己修改。当然你可以扩展为游戏手柄。
    def move(self, keyPressed):
        if keyPressed[K_a]:
            self.move_left()
        if keyPressed[K_w]:
            self.move_up()
        if keyPressed[K_s]:
            self.move_down()
        if keyPressed[K_d]:
            self.move_right()

	# 发射子弹,根据配制文件修改数量,请考虑对称性,子弹也不要太多,不然满屏子弹飞
    def shoot_bullets(self):
        if self.bShootCount == 2:
            Bullet(self.bulletType, (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
            Bullet(self.bulletType, (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
        if self.bShootCount == 4:
            Bullet(self.bulletType, (self.rect.left + 20, self.rect.top), self.groups[0], heroBulletGroup)
            Bullet(self.bulletType, (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
            Bullet(self.bulletType, (self.rect.right - 20, self.rect.top), self.groups[0], heroBulletGroup)
            Bullet(self.bulletType, (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)

	# 如果有强力子弹,也可以发射
    def shoot_power_bullets(self):
        if self.power_bullet_qty > 0:
            if self.bShootCount == 2:
                Bullet('P_BULLET', (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
                Bullet('P_BULLET', (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
                self.power_bullet_qty -= 2
            if self.bShootCount == 4:
                Bullet('P_BULLET', (self.rect.left + 20, self.rect.top), self.groups[0], heroBulletGroup)
                Bullet('P_BULLET', (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
                Bullet('P_BULLET', (self.rect.right - 20, self.rect.top), self.groups[0], heroBulletGroup)
                Bullet('P_BULLET', (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
                self.power_bullet_qty -= 4

            return True

        return False

	# 发射导弹
    def shoot_missiles(self):
        if self.mShootCount == 1:
            Bullet(self.missileType, (self.rect.centerx, self.rect.top), self.groups[0], heroBulletGroup)
        if self.bShootCount == 2:
            Bullet(self.missileType, (self.rect.centerx - 15, self.rect.top), self.groups[0], heroBulletGroup)
            Bullet(self.missileType, (self.rect.centerx + 15, self.rect.top), self.groups[0], heroBulletGroup)

	# 发射核弹
    def shoot_nuclear(self):
        if self.nuclearQty >= 1:
            Bullet('NUCLEAR', (self.rect.centerx, self.rect.top + 10), self.groups[0], nuclearGroup)
            self.nuclearQty -= 1
            return True
        
        return False
        
    # 捡到敌机丢下的包裹
    def pickup_package(self, pType):
        if pType == 'P_BULLET':
            self.power_bullet_qty += PACKAGES['P_BULLET']['QUANTITY']
        if pType == 'NUCLEAR':
            self.nuclearQty += 1
        if pType == 'DEFENCE':
            self.defence += PACKAGES['DEFENCE']['QUANTITY']

    # 躲子弹变形和恢复
    def transform(self, event):
        if event.type == KEYDOWN and event.key == K_SPACE:
            currentCenter = self.rect.center
            self.image = pygame.transform.smoothscale(self.image, (40, 80))
            self.rect.center = currentCenter
        elif event.type == KEYUP and event.key == K_SPACE:
            currentCenter = self.rect.center
            self.image = pygame.image.load(IMAGE_PATH + HERO_PLANES[self.type]['IMAGE']).convert_alpha()
            self.rect.center = currentCenter
	
    # sounds 为声音数组, 0 用于普通子弹、导弹, 1 用于核弹
    def shoot(self, keyPressed, sounds):
        if keyPressed[K_j]:
            self.shoot_bullets()
            sounds[0].play()

        if keyPressed[K_k]:
            self.shoot_missiles()
            sounds[0].play()

        if keyPressed[K_l]:
            if self.shoot_power_bullets():
                sounds[0].play()

        if keyPressed[K_i]:
            if self.shoot_nuclear():
                sounds[1].play()

    # 处理 heroPlane 被子弹击中 或者 被敌机撞击
    def was_collided(self, group):
        for sp in group:
            if pygame.sprite.collide_rect(self, sp):
                self.defence -= sp.destroyValue
                sp.kill()
                if self.defence <= 0:
                    return True

        return False

好了,英雄战机类和方法、以及处理相关键盘事件( 一共处理了 aswd, ijkl,space 九个键)。如果你想扩展别的功能,堆积木就好了。
仔细的朋友注意到了, HeroPlane类没有update方法,因为位置更新由用户来操作,这里是不需要的。当然你也可以添加update()方法,把特殊需要处理的事情放在这里,将会由战机所在的群的update()自动调用。
到这里,已经完整给出了 子弹类、敌机类、包裹类、英雄战机类的完整处理,有兴趣的朋友已经可以自己动手了,先准备好相关素材,然后编写个play() 来玩了。
哦,忘了,还有星空背景。
由于星空背景不是本人原创,是在原创的基础上进行了改写,以便能融入游戏。这里要感谢原创人。
星空背景使用了两个类: Star 类 和 Space,Space里有很多Star,对吧。

class Star(object):
    def __init__(self, x, y, speed):
        self.x = x
        self.y = y
        self.speed = speed
class Space:
    def __init__(self, targetSurf):
        self.targetSurf = targetSurf

        self.stars = self.get_stars()

    def get_stars(self):
        stars = []
        for n in range(10):
            x = randint(0, SCREEN_SIZE[0] - 1)
            y = randint(0, SCREEN_SIZE[1] - 1) + GAME_AREA_START_HEIGHT
            speed = randint(100, 300)

            stars.append(Star(x, y, speed))

        return stars

    def showspace(self, spaceClock):
        x = randint(0, SCREEN_SIZE[0])
        speed = randint(3, 15)

        star = Star(x, GAME_AREA_START_HEIGHT, speed)
        self.stars.append(star)

        time_passed_in_seconds = spaceClock.tick() / 1000.
        # 新产生的星星由于时间长(time_passed_in_seconds),因此移动速度快很多
        # 导致产生了很多不同速度的星星,当都朝一个方向运动时,看起来就像星空了。
        white = (255, 255, 255)
        for star in self.stars:
            new_y = star.y + time_passed_in_seconds * star.speed * 30
            pygame.draw.aaline(self.targetSurf, white, (star.x, new_y), (star.x, new_y + 2))  # 2 星星长度
            star.y = new_y

        def on_targetSurf(star):
            return star.y < SCREEN_SIZE[1]

        self.stars = list(filter(on_targetSurf, self.stars))

这里Star是一个点,有兴趣的朋友可以改为Sprite和Group来实现,将Star修改为一个小圆或者不同亮度的星星图片等。但也需要考虑Star太多后占用内存太多。

好了,本文就到这里,下一篇将会给出主函数,将这些东西组合起来玩游戏了。

你可能感兴趣的:(Pygame,Sprite,Group,Sprite)