Pygame飛機大戰爲什麼飛機與敵機碰撞後不再有圖片動態切換效果

這是原來的錯誤代碼(只是其中一部分,主模塊(未寫完的)),其中的錯誤是自定義的delay引起的

import pygame as pg
import sys
import traceback
import Plane
import Enemy
import Bullet

pg.init()
pg.mixer.init()
pm = pg.mixer
pg.display.set_caption('飛機大戰')                                                          #屏幕設置
running = True
clock = pg.time.Clock()
size = width,height = 480,700
screen = pg.display.set_mode(size)
bg = pg.image.load(r'images\background.png').convert()

pm.music.load('sound/game_music.ogg')                                               #載入音樂
pm.music.set_volume(0.05)
bullet_sound = pm.Sound('sound/bullet.wav')
bullet_sound.set_volume(0.2)
bomb_sound = pm.Sound('sound/use_bomb.wav')
bomb_sound.set_volume(0.2)
supply_sound = pm.Sound('sound/supply.wav')
supply_sound.set_volume(0.2)
get_bomb_sound = pm.Sound('sound/get_bomb.wav')
get_bomb_sound.set_volume(0.2)
get_bullet_sound = pm.Sound('sound/get_bullet.wav')
get_bullet_sound.set_volume(0.2)
upgrade_sound = pm.Sound('sound/upgrade.wav')
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pm.Sound('sound/enemy3_flying.wav')
enemy3_fly_sound.set_volume(0.7)
enemy1_down_sound = pm.Sound('sound/enemy1_down.wav')
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pm.Sound('sound/enemy2_down.wav')
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pm.Sound('sound/enemy3_down.wav')
enemy3_down_sound.set_volume(0.5)
me_down_sound = pm.Sound('sound/me_down.wav')
me_down_sound.set_volume(0.05)

def add_enemys1(group1,group2,num):
    for i in range(num):
        e1 = Enemy.enemy1(size)
        group1.add(e1)
        group2.add(e1)

def add_enemys2(group1,group2,num):
    for i in range(num):
        e1 = Enemy.enemy2(size)
        group1.add(e1)
        group2.add(e1)

def add_enemys3(group1,group2,num):
    for i in range(num):
        e1 = Enemy.enemy3(size)
        group1.add(e1)
        group2.add(e1)

def add_bullets_1(group1,group2,num,plane):
    for i in range(num):
        e1 = Bullet.Bullet_1(size,plane)
        group1.add(e1)
        group2.add(e1)        

def main(): 
    me_switch = True                  #我方飛機動態切換
    delay = 10
    pm.music.play(-1)                 #-1意爲無限循環此音樂
    bullets_1 = []                         #創建對象容器
    enemys1 = []
    enemys2 = []
    enemys3 = []

    me = Plane.MyPlane(size)                     #我方飛機實例化

    groups = pg.sprite.Group()

    enemys1 = pg.sprite.Group()                 #生成小型敵機
    add_enemys1(enemys1,groups,15)

    enemys2 = pg.sprite.Group()                 #生成中型敵機
    add_enemys2(enemys2,groups,15)

    enemys3 = pg.sprite.Group()                 #生成大型敵機
    add_enemys3(enemys3,groups,15)
    
    bullets_1 = pg.sprite.Group()                 #生成子彈
    
    add_bullets_1(bullets_1,groups,150,me)

    e1_destory_index = 0                            #毀滅圖像集合索引
    e2_destory_index = 0
    e3_destory_index = 0
    me_destory_index = 0

    while running:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()                    #這個必須在sys.quit前面,否則程序衝突
                sys.exit()

        key_pressed = pg.key.get_pressed()      #獲得哪些按鍵被長按
        
        if key_pressed[pg.K_w]:                         #遊戲操作
            me.moveUp()
        if key_pressed[pg.K_s]:
            me.moveDown()
        if key_pressed[pg.K_a]:
            me.moveLeft()
        if key_pressed[pg.K_d]:
            me.moveRight()

        screen.blit(bg,(0,0))

        collide = pg.sprite.spritecollide(me,groups,False,pg.sprite.collide_mask)          #碰撞檢測
        if collide:
            me.alive = False
            for each in collide:
                each.alive = False

        delay -= 1                                              #我方飛機動態切換
        if me.alive:
            if me_switch:
                screen.blit(me.image1,me.rect)
            else:
                screen.blit(me.image2,me.rect)
            if not delay :
                me_switch = not me_switch
                delay = 10
        else:       #毀滅
            if not (delay % 3):
                me_down_sound.play()
                screen.blit(me.destory_images[me_destory_index],me.rect)
                me_destory_index = (me_destory_index+1) % 4
                if me_destory_index == 0:
                    me.reset()

        for each in bullets_1:
            if not (delay%10):
                each.Flying(me)
            screen.blit(each.image,each.rect)
            
        for each in enemys3:                               #引入大型敵機
            if each.alive:
                each.moveEnemy3(enemy3_fly_sound)
                if each.rect.bottom == -0.5*each.rect.height or each.rect.bottom == 0:
                    enemy3_fly_sound.play(-1)
                if me_switch:
                    screen.blit(each.image1,each.rect)
                else:
                    screen.blit(each.image2,each.rect)
            else:       #毀滅
                if not (delay % 3):
                    enemy3_down_sound.play()
                    enemy3_fly_sound.stop()
                    screen.blit(each.destory_images[e3_destory_index],each.rect)
                    e3_destory_index = (e3_destory_index+1) % 6
                    if e3_destory_index == 0:
                        each.reset( )

        for each in enemys2:                               #引入中型敵機
            if each.alive:
                each.moveEnemy2()
                screen.blit(each.image1,each.rect)
            else:       #毀滅
                if not (delay % 3):
                    enemy2_down_sound.play()
                    screen.blit(each.destory_images[e2_destory_index],each.rect)
                    e2_destory_index = (e2_destory_index+1) % 4
                    if e2_destory_index == 0:
                        each.reset( )

        for each in enemys1:                               #引入小型敵機
            if each.alive:
                each.moveEnemy1()
                screen.blit(each.image1,each.rect)
            else:       #毀滅
                if not (delay % 3):
                    enemy1_down_sound.play()
                    screen.blit(each.destory_images[e1_destory_index],each.rect)
                    e1_destory_index = (e1_destory_index+1) % 4
                    if e1_destory_index == 0:
                        each.reset( )
            
        pg.display.flip()
        clock.tick(60)

if __name__ == '__main__':
    try:
        main( )
    except SystemExit:
        pass
    except :
        traceback.print_exc()
        pg.quit()
        input()`在這裏插入代碼片`

其中錯誤的主要部分如下

delay = 10
.......
if collide:
            me.alive = False
            for each in collide:
                each.alive = False

        delay -= 1                                              #我方飛機動態切換
        if me.alive:
            if me_switch:
                screen.blit(me.image1,me.rect)
            else:
                screen.blit(me.image2,me.rect)
            if not delay :
                me_switch = not me_switch
                delay = 10
        else:       #毀滅
            if not (delay % 3):
                me_down_sound.play()
                screen.blit(me.destory_images[me_destory_index],me.rect)
                me_destory_index = (me_destory_index+1) % 4
                if me_destory_index == 0:
                    me.reset()

其中的delay賦值太小(delay=10),進行碰撞檢測後飛機處於me.alive = False的狀態,而此時的幀數delay仍然在隨着pygame的幀率隨時間減少,並且這一塊代碼中if me.alive:是一直不會運行的,導致其中的if not delay:也失去了他本來具有的檢測功能。

碰撞檢測的時間較長(我做了測試計算,在後面的飛機爆炸動畫中算出大約12幀左右),因此在這段時間內,delay早已被減小的小過了0,因此在碰撞後,if not delay:
已經不再具有檢測作用,從而導致在其中的飛機動態開關不再會打開或關閉,導致了飛機與敵機碰撞後不再有圖片動態切換效果。

既然原因已經分析出來,那麼解決方案就顯而易見了。

解決方案1:

直接把if not delay: 改成 if (delay <= 0): 即可,這個方法的好處是不需去改變其他對象或者參數的值。

解決方案2:

把代碼中的delay = 10 改爲更大的數,多大自己具體決定,但值得注意的是,下面的if not delay:也需要修改,否則飛機動態切換一次的幀數就隨之變大了(以及其他涉及delay變量的對象也可能會隨之改變),可以改成常用的if not (delay%10): 方法來解決。

從這個解決方案可以反思到程序員應該具備的一個特點就是 “ 不是哪裏出錯,就像打補丁一樣補上去,而是認真分析代碼,把根本性的原因找出來”。否則很可能像解決方案2一樣只記得了把delay改成更大就好,卻忘記了去考慮受其影響的對象,因此程序員很重要的應該就是這種全局觀。

如有其它問題歡迎評論討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章