上一篇讲解了动态背景,并创建了飞机的基类。本篇继续讲解玩家飞机类的创建及其控制方法。
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
用来保存无敌状态,玩家飞机刷新时有一个无敌时间,避免一刷新就被子弹打中,玩家没有反应时间。
接下来要添加系统事件控制函数:包含对飞机移动、窗口关闭按钮、按钮的控制。
# 相应键盘、鼠标、窗口关闭按钮等
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.type
和 event.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)
运行脚本就可以控制玩家飞机了,不过仍然没有显示子弹,因为没有调用子弹的 move
和 display
方法。
子弹、敌机、补给包,都有一个越界问题,就是飞出了显示区域,所以我们把 move
和 display
方法调用封装到一个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)
,再次运行,就可以控制飞机移动并发射子弹了。