上一篇講解了動態(tài)背景,并創(chuàng)建了飛機(jī)的基類啸澡。本篇繼續(xù)講解玩家飛機(jī)類的創(chuàng)建及其控制方法飞崖。
class HeroPlane(BasePlane):
def __init__(self, pygame_screen, bullets):
BasePlane.__init__(self, pygame_screen, (210, 700), Image_HeroPlane, 5, bullets)
self.moveToLeft = False # 控制玩家飛機(jī)移動位置
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 # 無敵時(shí)間
self.invincibleTiming = 0 # 無敵倒計(jì)時(shí)
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) # 飛機(jī)普通狀態(tài)顯示的圖片
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) # 飛機(jī)往前飛狀態(tài)顯示的圖片
self.y -= self.moveSpeed
def fire(self):
# 玩家飛機(jī)開火
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:
# 無敵時(shí)間到
self.invincibleTiming = 0
self.invincible = False
else:
# 無敵倒計(jì)時(shí)顯示
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): #玩家飛機(jī)子彈
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): #敵機(jī)子彈
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()
創(chuàng)建飛機(jī)對象需要傳入子彈對象,所以這里把子彈類的代碼也一起發(fā)了上來德撬。
玩家飛機(jī)繼承基類 BasePlane
的基礎(chǔ)上铲咨,增加了一些特有屬性和方法:
moveTo...
4 個(gè)屬性分別存儲移動方向。
invincible
用來保存無敵狀態(tài)蜓洪,玩家飛機(jī)刷新時(shí)有一個(gè)無敵時(shí)間纤勒,避免一刷新就被子彈打中,玩家沒有反應(yīng)時(shí)間隆檀。
接下來要添加系統(tǒng)事件控制函數(shù):包含對飛機(jī)移動摇天、窗口關(guān)閉按鈕粹湃、按鈕的控制。
# 相應(yīng)鍵盤泉坐、鼠標(biāo)为鳄、窗口關(guān)閉按鈕等
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: # 判斷是否是點(diǎn)擊了退出按鈕
exit()
if event.type == KEYDOWN and hero.live > 0: # 鍵盤按鍵按下,玩家飛機(jī)掛了腕让,就不相應(yīng)了
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(): # 關(guān)閉背景音樂
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(): # 關(guān)閉音效
global Sound_IsPlay # 修改全局變量
Sound_IsPlay = False if Sound_IsPlay else True # 三目運(yùn)算孤钦,更加簡潔
return ''
pygame.event.get()
獲取系統(tǒng)事件,返回的是Event對象,比如按鍵彈起事件
<Event(3-KeyUp {'key': 276, 'mod': 0, 'scancode': 75, 'window': None})>
通過 event.type
和 event.key
兩個(gè)屬性就可以判斷玩家對按鍵做了什么操作纯丸,然后修改HeroPlane
對象偏形,飛機(jī)移動的相關(guān)屬性,這樣飛機(jī)調(diào)用move
方法就會對應(yīng)的改變飛機(jī)坐標(biāo)液南,從而達(dá)到控制的目的壳猜。
更新 Main()函數(shù),添加飛機(jī)相關(guān)控制方法的調(diào)用
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() #生成飛機(jī)移動后位置
hero.bulletCoolDown() # 玩家飛機(jī)子彈冷卻
hero.fire() # 玩家飛機(jī)發(fā)射子彈
hero.display() #繪制玩家飛機(jī)
pygame.display.update()
MainControl(hero, screen)
運(yùn)行腳本就可以控制玩家飛機(jī)了滑凉,不過仍然沒有顯示子彈统扳,因?yàn)闆]有調(diào)用子彈的 move
和 display
方法。
子彈畅姊、敵機(jī)咒钟、補(bǔ)給包,都有一個(gè)越界問題若未,就是飛出了顯示區(qū)域朱嘴,所以我們把 move
和 display
方法調(diào)用封裝到一個(gè)IsOverBound函數(shù)中和越界判斷一起處理。
def IsOverBound(*params): # 判斷子彈粗合、敵機(jī)是否越界,包括子彈移動
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): # 當(dāng)前判斷的是敵機(jī)子彈萍嬉,
objs[index].move()
objs[index].display()
def IsOverBound(*params)
這里用到不定參數(shù),因?yàn)檫@個(gè)函數(shù)包括了敵機(jī)隙疚、補(bǔ)給包的判斷壤追,但這兩個(gè)對象我們還沒有創(chuàng)建,如果固定的參數(shù)就無法對子彈進(jìn)行調(diào)試供屉。
isinstance(objs[index], EnemyBullet)
通過isinstance函數(shù)來判斷行冰,當(dāng)前處理的是哪個(gè)對象,來進(jìn)行差異控制伶丐。
Main()
函數(shù)中添加調(diào)用 IsOverBound(Bullets)
悼做,再次運(yùn)行,就可以控制飛機(jī)移動并發(fā)射子彈了哗魂。