pygame飞机大战开发实录5

上一篇讲解了动态背景,并创建了飞机的基类。本篇继续讲解玩家飞机类的创建及其控制方法。

class HeroPlane(BasePlane):
    def __init__(self, pygame_screen, bullets):
        BasePlane.__init__(self, pygame_screen, (210, 700), Image_HeroPlane, 5, bullets)
        self.moveToLeft = False  # 控制玩家飞机移动位置
        self.moveToRight = False
        self.moveToUp = False
        self.moveToDown = False
        self.keepFire = False
        self.moveSpeed = 3
        self.health = 6
        self.maxHealth = 6
        self.live = 5
        self.invincible = True
        self.invincibleTime = 400  # 无敌时间
        self.invincibleTiming = 0  # 无敌倒计时
        self.bulletType = "normal"
        self.__crate_images()  # 添加爆炸动画图片组
    def __crate_images(self):
        for i in range(4):
            self.bombList.append(pygame.image.load("./res/hero_blowup_n" + str(i + 1) + ".png"))
    def move(self):
        self.image = pygame.image.load(Image_HeroPlane)  # 飞机普通状态显示的图片
        if self.moveToRight and self.x < 480 - self.w:  # 移动越界判断
            self.x += self.moveSpeed
        if self.moveToLeft and self.x > self.moveSpeed:
            self.x -= self.moveSpeed
        if self.moveToDown and self.y < 852 - self.h:
            self.y += self.moveSpeed
        if self.moveToUp and self.y > self.moveSpeed:
            self.image = pygame.image.load(Image_HeroPlaneUp)  # 飞机往前飞状态显示的图片
            self.y -= self.moveSpeed
    def fire(self):
        # 玩家飞机开火
        if self.keepFire and self.bulletCdOk:
            #PlaySound(Sound_HeroFire)
            if self.bulletType == "normal":
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) - 2, self.y - 2), "line"))
            elif self.bulletType == "doublebullet":
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) - 34, self.y + 20), "line"))
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) + 28, self.y + 20), "line"))
            elif self.bulletType == "shotbullet":
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) - 34, self.y + 20), "Lbiasline"))
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) + 28, self.y + 20), "Rbiasline"))
                self.bulletList.append(Bullet(self.screen, (self.x + (self.w / 2) - 2, self.y - 2), "line"))
            self.bulletCoolDownstate = 1
            self.bulletCdOk = False
    def display(self):
        if self.invincible:
            self.invincibleTiming += 1
            if self.invincibleTiming == self.invincibleTime:
                # 无敌时间到
                self.invincibleTiming = 0
                self.invincible = False
            else:
                # 无敌倒计时显示
                fontColor = (80, 80, 80)
                fontObj = pygame.font.Font(Font_Consola, 18)
                showinvincibleTiming = fontObj.render(
                    str(int((self.invincibleTime - self.invincibleTiming) // (self.invincibleTime / 10))), True,
                    fontColor)
                showinvincibleTimingObj = showinvincibleTiming.get_rect()
                showinvincibleTimingObj.center = (self.x - 5, self.y + 20)
                self.screen.blit(showinvincibleTiming, showinvincibleTimingObj)
        BasePlane.display(self)
        # 血条显示
        for i in range(self.health):
            self.screen.blit(self.healthImage, (self.x - 10, self.y + self.h - 44 - i * 9))            
class BaseBullet(Base):
    def display(self):
        self.screen.blit(self.image, (self.x, self.y))
class Bullet(BaseBullet): #玩家飞机子弹
    def __init__(self, pygame_screen,postion,movingpath):
        Base.__init__(self, pygame_screen, postion, Image_HeroBullet)
        self.movingPath = movingpath  #子弹飞行路线
    def move(self):
        if self.movingPath == "line":
           self.y -= 10
        elif self.movingPath == "Lbiasline":
            self.y -= 10
            self.x -= 3
        elif self.movingPath == "Rbiasline":
            self.y -= 10
            self.x += 3
class EnemyBullet(BaseBullet): #敌机子弹
    def __init__(self, pygame_screen, postion):
        Base.__init__(self, pygame_screen,postion, Image_EnemyBullet)
    def move(self):
        self.y += 4
    def __str__(self):
        return isinstance()
创建飞机对象需要传入子弹对象,所以这里把子弹类的代码也一起发了上来。

玩家飞机继承基类 BasePlane的基础上,增加了一些特有属性和方法:
moveTo...4 个属性分别存储移动方向。
invincible用来保存无敌状态,玩家飞机刷新时有一个无敌时间,避免一刷新就被子弹打中,玩家没有反应时间。
pygame飞机大战开发实录5_第1张图片


接下来要添加系统事件控制函数:包含对飞机移动、窗口关闭按钮、按钮的控制。

# 相应键盘、鼠标、窗口关闭按钮等
def MainControl(hero, pygame_screen, *params):
    if len(params) > 1:
        cbsound = params[0]
        cbmusic = params[1]
    else:
        cbsound = False
        cbmusic = False
    for event in pygame.event.get():
        if event.type == QUIT:  # 判断是否是点击了退出按钮
            exit()
        if event.type == KEYDOWN and hero.live > 0:  # 键盘按键按下,玩家飞机挂了,就不相应了
            if event.key == K_a or event.key == K_LEFT:
                hero.moveToLeft = True
            elif event.key == K_d or event.key == K_RIGHT:
                hero.moveToRight = True
            elif event.key == K_w or event.key == K_UP:
                hero.moveToUp = True
            elif event.key == K_s or event.key == K_DOWN:
                hero.moveToDown = True
            elif event.key == K_SPACE:
                hero.keepFire = True
            elif event.key == K_ESCAPE:
                return Paused(pygame_screen)
        elif event.type == KEYUP:  # 键盘按键弹起
            if event.key == K_a or event.key == K_LEFT:
                hero.moveToLeft = False
            elif event.key == K_d or event.key == K_RIGHT:
                hero.moveToRight = False
            elif event.key == K_w or event.key == K_UP:
                hero.moveToUp = False
            elif event.key == K_s or event.key == K_DOWN:
                hero.moveToDown = False
            elif event.key == K_SPACE:
                hero.keepFire = False
        if cbmusic:
            if event.type == pygame.MOUSEBUTTONDOWN and cbmusic.isOver():  # 关闭背景音乐
                if pygame.mixer.music.get_busy() == 1:
                    pygame.mixer.music.stop()
                else:
                    pygame.mixer.music.play(-1, 0)
        if cbsound:
            if event.type == pygame.MOUSEBUTTONDOWN and cbsound.isOver():  # 关闭音效
                global Sound_IsPlay  # 修改全局变量
                Sound_IsPlay = False if Sound_IsPlay else True  # 三目运算,更加简洁
    return ''

pygame.event.get()获取系统事件,返回的是Event对象,比如按键弹起事件


通过 event.typeevent.key两个属性就可以判断玩家对按键做了什么操作,然后修改HeroPlane对象,飞机移动的相关属性,这样飞机调用move方法就会对应的改变飞机坐标,从而达到控制的目的。


更新 Main()函数,添加飞机相关控制方法的调用

def main():
    pygame.init()
    screen = pygame.display.set_mode((480, 852), 0, 32)
    # 添加背景
    Bg = BackGround(screen, Image_Background, 'dynamic')
    Bullets = []
    hero = HeroPlane(screen, Bullets)
    while True:
        Bg.display()
        hero.move()  #生成飞机移动后位置
        hero.bulletCoolDown()  # 玩家飞机子弹冷却       
        hero.fire()        # 玩家飞机发射子弹
        hero.display()        #绘制玩家飞机       
        pygame.display.update()
        MainControl(hero, screen)

运行脚本就可以控制玩家飞机了,不过仍然没有显示子弹,因为没有调用子弹的 movedisplay方法。


子弹、敌机、补给包,都有一个越界问题,就是飞出了显示区域,所以我们把 movedisplay方法调用封装到一个IsOverBound函数中和越界判断一起处理。

def IsOverBound(*params):  # 判断子弹、敌机是否越界,包括子弹移动
    if len(params) < 1:
        return
    objGroup = [param for param in params]
    for objs in objGroup:
        for index in range(len(objs) - 1, -1, -1):
            if objs[index].y > Screen_Height or objs[index].y < - 20:
                del (objs[index])
            else:
                if isinstance(objs[index], EnemyBullet) or isinstance(objs[index], Bullet):  # 当前判断的是敌机子弹,
                    objs[index].move()
                    objs[index].display()

def IsOverBound(*params)这里用到不定参数,因为这个函数包括了敌机、补给包的判断,但这两个对象我们还没有创建,如果固定的参数就无法对子弹进行调试。
isinstance(objs[index], EnemyBullet)通过isinstance函数来判断,当前处理的是哪个对象,来进行差异控制。
Main()函数中添加调用 IsOverBound(Bullets),再次运行,就可以控制飞机移动并发射子弹了。
pygame飞机大战开发实录5_第2张图片


本篇讲解玩家飞机控制方法,以及子弹越界判断。下一篇继续讲解敌机、补给包、Boss的生成及控制。

你可能感兴趣的:(Python-pygame)