1. 程式人生 > >外星人大戰----------------------遊戲開發(四)

外星人大戰----------------------遊戲開發(四)

前面已經實現外星人的移動,現在開始完成射殺外星人。我們將要使用sprite.groupcollide()檢測兩個編組的碰撞。我們要在碰撞的時候立馬就讓外星人消失,所以在更新位置的時候就檢測有無碰撞。


在功能模組檢測子彈與外星人,方法sprite.groupcollide()將每顆子彈的rect同外星人的rect比較,返回一個字典,其中包含發生碰撞的子彈與外星人,在這個字典裡每個鍵都是一顆子彈,而相應的值都是被擊中的外星人。這樣兩者就相互對應起來了。

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
        bullets.update()
        for bullet in bullets.copy():
                if bullet.rect.bottom<=0:
                          bullets.remove(bullet)
    #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  

  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,aliens):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()


#對於外星人到達邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

在函式update_bullets()新增一行程式碼,這行程式碼遍歷編組裡bullets的所有子彈,再遍歷aliens的每個外星人,當有兩者重疊的時候,groupcollide()就在它返回的字典中新增鍵-值。兩個實參true告知pygame刪除發生碰撞的子彈與外星人。(第一個實參true是代表的是刪除子彈,第二個實參true是外星人。我們也可以設定子彈不刪除,外星人刪除,只要子彈與外星人碰撞,就會外星人消失,子彈可以一直移動到頂端,就把第一個布林實參設為False,第二個布林實參設為true)

主程式:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame

from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group


def run_game():
    pygame.init()  #初始化,建立螢幕物件
    ai_settings=Setting()    #建立一個800*800的螢幕
    screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))  
    pygame.display.set_caption("Alien Invasion")   #對於這個視窗的命名為Alien Invasion

    ship=Ship(ai_settings,screen)   #建立飛船
    bullets=Group()
    aliens=Group()
    gf.creat_fleet(ai_settings,screen,ship,aliens)

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        gf.update_bullets(aliens,bullets)
        gf.update_aliens(ai_settings,aliens)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

執行程式,看看驗證結果:

生成新的外星人:

當射擊的外星人都沒有了,就要產生新的外星人,首先,我們要去確定外星人都被殺死,就要檢查aliens編組是否為空,如果為空,就要呼叫creat_fleet().我們要在update_bullets()裡執行檢查,因為外星人在這裡被擊殺,

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(ai_settings,screen,ship,aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
        bullets.update()
        for bullet in bullets.copy():
                if bullet.rect.bottom<=0:
                          bullets.remove(bullet)
    #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  
        
        if len(aliens)==0:
                bullets.empty()  #刪除現有的子彈並新建新的外星人群
                creat_fleet(ai_settings,screen,ship,aliens)

  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,aliens):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()


#對於外星人到達邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

主程式:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame

from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group


def run_game():
    pygame.init()  #初始化,建立螢幕物件
    ai_settings=Setting()    #建立一個800*800的螢幕
    screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))  
    pygame.display.set_caption("Alien Invasion")   #對於這個視窗的命名為Alien Invasion

    ship=Ship(ai_settings,screen)   #建立飛船
    bullets=Group()
    aliens=Group()
    gf.creat_fleet(ai_settings,screen,ship,aliens)

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        gf.update_bullets(ai_settings,screen,ship,aliens,bullets)
        gf.update_aliens(ai_settings,aliens)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

執行程式,驗證結果:

當我射殺完外星人後,就會出現新的外星人群。

重構功能模組裡的update_bullets():

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(ai_settings,screen,ship,aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
        bullets.update()
        for bullet in bullets.copy():
                if bullet.rect.bottom<=0:
                          bullets.remove(bullet)
         check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets)   


def check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets):
        #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  
        
        if len(aliens)==0:
                bullets.empty()  #刪除現有的子彈並新建新的外星人群
                creat_fleet(ai_settings,screen,ship,aliens)


  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,aliens):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()


#對於外星人到達邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

驗證結果:沒有問題

現在看來整個遊戲開發的大體框架都已經完成了,現在可以實現移動飛船,發射子彈,子彈射殺外星人,外星人會重新補全等大概的功能,但是這個遊戲會一直繼續下去,除非你點選退出,但一個沒有輸贏的遊戲大概會很無聊,所以接下來就來設定如何結束遊戲,結束遊戲有以下幾種情況,1.不想玩了,直接點選退出鍵就結束遊戲。2.如果玩家在限制的時間內未射殺完外星人,或者外星人撞到飛船以及外星人到達螢幕底端,飛船會被摧毀,最多可提供三架飛船,飛船摧毀完遊戲自動結束。

1.監測外星人和飛船相撞的情況,就像子彈和外星人的相撞一樣,在更新外星人的位置後就檢測有無相撞。現在就是簡單檢查有沒有撞到,對於後續的行為先不設定。

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(ai_settings,screen,ship,aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
	bullets.update()
	for bullet in bullets.copy():
		if bullet.rect.bottom<=0:
			bullets.remove(bullet)
	check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets)   


def check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets):
        #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  
        
        if len(aliens)==0:
                bullets.empty()  #刪除現有的子彈並新建新的外星人群
                creat_fleet(ai_settings,screen,ship,aliens)


  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,ship,aliens):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()

     #監測外星人和飛船的相撞
	if pygame.sprite.spritecollideany(ship,aliens):
		print("ship hit!!!")



#對於外星人到達邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

方法sprite.spritecollideany()接受兩個實參,一個精靈和一個編組,它檢查編組是否有成員與精靈發生了碰撞,找到與精靈發生碰撞的成員後就停止遍歷編組。如果沒有發生碰撞,返回none。 

主程式:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame

from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group


def run_game():
    pygame.init()  #初始化,建立螢幕物件
    ai_settings=Setting()    #建立一個800*800的螢幕
    screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))  
    pygame.display.set_caption("Alien Invasion")   #對於這個視窗的命名為Alien Invasion

    ship=Ship(ai_settings,screen)   #建立飛船
    bullets=Group()
    aliens=Group()
    gf.creat_fleet(ai_settings,screen,ship,aliens)

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        gf.update_bullets(ai_settings,screen,ship,aliens,bullets)
        gf.update_aliens(ai_settings,ship,aliens)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

執行程式。看看驗證結果:

按上面的程式碼現在已經檢測到相撞了,現在就在來響應下相撞後該有什麼行為;現在建立一個新的飛船例項 ,記錄遊戲飛船被撞毀幾次

建立一個用於記錄跟蹤遊戲資訊的新類Gamestats

#跟蹤遊戲統計資訊的類
class GameStats():
    def __init__(self,ai_settings):
        self.ai_settings=ai_settings
        self.reset_stats()
        self.game_active=True     #遊戲活動標誌

    def reset_stats(self):      #初始化在遊戲裡可能會變化的統計資訊
        self.ships_left=self.ai_settings.ship_limit
        

建立一個GameStats的例項,每當開始新遊戲的時候,重置設定一些統計資訊,當前只有一項統計資訊ships_left。

修改設定類;

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#儲存外星人遊戲開發的設定
class Setting():
    def __init__(self):
        self.screen_width=800    #設定螢幕高度寬度,背景顏色
        self.screen_height=600
        self.bg_color=(230,230,230)
        #飛船設定
        self.ship_speed_factor=1.5   #設定飛船移動
        self.ship_limit=3           #設定飛船數量
        #子彈設定
        self.bullet_speed_factor=1
        self.bullet_width=3
        self.bullet_height=15
        self.bullet_color=(0,0,255)
        self.bullets_allowed=3
        #外星人設定
        self.alien_speed_factor=1
        self.fleet_drop_speed=5
        self.fleet_direction=1    #fleet_direction 為1表示右移,為-1表示左移
        

修改功能模組:當外星人撞到飛船,將飛船的數量減一,建立一群新的外星人,並將飛船放置到初始位置。

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(ai_settings,screen,ship,aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
	bullets.update()
	for bullet in bullets.copy():
		if bullet.rect.bottom<=0:
			bullets.remove(bullet)
	check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets)   


def check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets):
        #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  
        
        if len(aliens)==0:
                bullets.empty()  #刪除現有的子彈並新建新的外星人群
                creat_fleet(ai_settings,screen,ship,aliens)


  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,stats,screen,ship,aliens,bullets):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()

     #監測外星人和飛船的相撞
	if pygame.sprite.spritecollideany(ship,aliens):
		ship_hit(ai_settings,stats,screen,ship,aliens,bullets)

#響應被外星人撞到的飛船
def ship_hit(ai_settings,stats,screen,ship,aliens,bullets):
        stats.ships_left-=1
        aliens.empty()      #清空外星人列表
        bullets.empty()     #清空子彈列表
        #建立新的外星人,飛船放入中間
        creat_fleet(ai_settings,screen,ship,aliens)
        ship.center_ship()
        
        sleep(0.5)        #暫停


#對於外星人到達邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

 從模組time匯入sleep,用於讓遊戲暫停;

修改ship類:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#建立飛船類
import pygame

class Ship(): 
	def __init__(self,ai_settings,screen):
		self.screen=screen
		self.ai_settings=ai_settings

     #圖片存在images資料夾下,名字是ship.bmp    
		self.image=pygame.image.load('images/ship.bmp')  
		self.rect=self.image.get_rect()
		self.screen_rect=screen.get_rect()

		self.rect.centerx=self.screen_rect.centerx
		self.rect.bottom=self.screen_rect.bottom

		self.center=float(self.rect.centerx)   #因為rect的centerx只能儲存整數值,在飛船的center儲存小數值
		self.moving_right=False            #設定移動標誌
		self.moving_left=False

	def update(self):
		if self.moving_right and self.rect.right <self.screen_rect.right:        #根據移動標誌,來調整位置
			self.center+=self.ai_settings.ship_speed_factor      #更新飛船的center的值,不是rect
			
		if self.moving_left and self.rect.left>0:
			self.center-=self.ai_settings.ship_speed_factor
		
		self.rect.centerx=self.center    #來更新rect物件
        

	def blitme(self):
		self.screen.blit(self.image,self.rect)  
        
	def center_ship(self):
		self.center=self.screen_rect.centerx

修改主程式:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame

from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from game_stats import GameStats


def run_game():
    pygame.init()  #初始化,建立螢幕物件
    ai_settings=Setting()    #建立一個800*800的螢幕
    screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))  
    pygame.display.set_caption("Alien Invasion")   #對於這個視窗的命名為Alien Invasion
    
    stats=GameStats(ai_settings)    #建立一個用於儲存統計資訊的例項
    ship=Ship(ai_settings,screen)   #建立飛船
    bullets=Group()
    aliens=Group()
    gf.creat_fleet(ai_settings,screen,ship,aliens)

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        gf.update_bullets(ai_settings,screen,ship,aliens,bullets)
        gf.update_aliens(ai_settings,stats,screen,ship,aliens,bullets)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

執行程式,驗證結果如下:

當相撞後,飛船與外星人重新出現,飛船在初始位置

2.有外星人到達螢幕底端:

上面已經處理相撞的情況,現在來處理到達底端的時候,

修改功能模組,新增一個檢查函式,來檢查是否到達底部

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#遊戲的功能模組,包括響應鍵盤滑鼠事件,移動飛船等

import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep

def check_keydown_events(event,ai_settings,screen,ship,bullets):           #響應按鍵
	if event.key==pygame.K_RIGHT:
		ship.moving_right=True    #改變標誌位
	elif event.key==pygame.K_LEFT:
		ship.moving_left=True
	elif event.key==pygame.K_SPACE:      #響應按空格鍵
                fire_bullet(ai_settings,screen,ship,bullets)

def fire_bullet(ai_settings,screen,ship,bullets):   #發射子彈
	if len(bullets)<ai_settings.bullets_allowed:    
		new_bullet=Bullet(ai_settings,screen,ship)
		bullets.add(new_bullet)

		
		
def check_keyup_events(event,ship):   #響應按鍵鬆開
	if event.key==pygame.K_RIGHT:
		ship.moving_right=False
	elif event.key==pygame.K_LEFT:
		ship.moving_left=False
	

def check_events(ai_settings,screen,ship,bullets):     #響應鍵盤和滑鼠事件
	for event in pygame.event.get():
		if event.type==pygame.QUIT:
			sys.exit() 
		elif event.type==pygame.KEYDOWN:
			check_keydown_events(event,ai_settings,screen,ship,bullets)

		elif event.type==pygame.KEYUP:       #監測是否放開鍵盤
			check_keyup_events(event,ship)
         
def update_screen(ai_settings,screen,ship,aliens,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()
	aliens.draw(screen)

	pygame.display.flip()

def update_bullets(ai_settings,screen,ship,aliens,bullets):  #更新子彈的位置,並刪除已消失的子彈
        bullets.update()
        for bullet in bullets.copy():
                if bullet.rect.bottom<=0:
                          bullets.remove(bullet)
         check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets)   


def check_bullet_alien_collisions(ai_settings,screen,ship,aliens,bullets):
        #檢查是否兩者碰撞,是的話,刪除相應的子彈與外星人
        collisions=pygame.sprite.groupcollide(bullets,aliens,True,True)  
        
        if len(aliens)==0:
                bullets.empty()  #刪除現有的子彈並新建新的外星人群
                creat_fleet(ai_settings,screen,ship,aliens)


  #建立外星人群
def get_number_aliens_x(ai_settings,alien_width):     #計算每行可以放入多少外星人
        available_space_x=ai_settings.screen_width-2*alien_width
        number_aliens_x=int(available_space_x/(2*alien_width))
        return number_aliens_x 

def creat_alien(ai_settings,screen,aliens,alien_number,row_number):
        alien=Alien(ai_settings,screen)    #建立一個外星人,放入當前行
        alien_width=alien.rect.width
        alien.x=alien_width+2*alien_width*alien_number
        alien.rect.x=alien.x
        alien.rect.y=alien.rect.height+2*alien.rect.height*row_number
        aliens.add(alien)

#計算螢幕可以放入多少行
def get_number_rows(ai_settings,ship_height,alien_height):
        available_space_y=(ai_settings.screen_height-(3*alien_height)-ship_height)
        number_rows=int(available_space_y/(2*alien_height))
        return number_rows

def creat_fleet(ai_settings,screen,ship,aliens):
        alien=Alien(ai_settings,screen)    #建立一個外星人,計算一行可以容納多少
        number_aliens_x=get_number_aliens_x(ai_settings,alien.rect.width)
        number_rows=get_number_rows(ai_settings,ship.rect.height,alien.rect.height)

        for row_number in range(number_rows):  
            for alien_number in range(number_aliens_x):
                creat_alien(ai_settings,screen,aliens,alien_number,row_number)

#更新外星人的位置
def update_aliens(ai_settings,stats,screen,ship,aliens,bullets):
	check_fleet_edges(ai_settings,aliens)
	aliens.update()
        check_aliens_bottom(ai_settings,stats,screen,ship,aliens,bullets)

     #監測外星人和飛船的相撞
        if pygame.sprite.spritecollideany(ship,aliens):
                ship_hit(ai_settings,stats,screen,ship,aliens,bullets)

#響應被外星人撞到的飛船
def ship_hit(ai_settings,stats,screen,ship,aliens,bullets):
       if stats.ships_left>0:
            stats.ships_left-=1
            aliens.empty()      #清空外星人列表
            bullets.empty()     #清空子彈列表
            #建立新的外星人,飛船放入中間
            creat_fleet(ai_settings,screen,ship,aliens)
            ship.center_ship()
            sleep(0.5)        #暫停
       else:
            stats.game_active=False

#檢查是否有外星人到達螢幕底端
def check_aliens_bottom(ai_settings,stats,screen,ship,aliens,bullets):
        screen_rect=screen.get_rect()
        for alien in aliens.sprites():
            if alien.rect.bottom>=screen_rect.bottom:
                ship_hit(ai_settings,stats,screen,ship,aliens,bullets)
                break

#對於外星人到達左右邊緣採取的措施:
def check_fleet_edges(ai_settings,aliens):
	for alien in aliens.sprites():
		if alien.check_edges():
			change_fleet_direction(ai_settings,aliens)
			break
			
#下移外星人
def change_fleet_direction(ai_settings,aliens):
	for alien in aliens.sprites():
		alien.rect.y+=ai_settings.fleet_drop_speed
	ai_settings.fleet_direction*=-1
	

主程式如下:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
import pygame

from setting import Setting
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from game_stats import GameStats


def run_game():
    pygame.init()  #初始化,建立螢幕物件
    ai_settings=Setting()    #建立一個800*800的螢幕
    screen=pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))  
    pygame.display.set_caption("Alien Invasion")   #對於這個視窗的命名為Alien Invasion
    
    stats=GameStats(ai_settings)    #建立一個用於儲存統計資訊的例項
    ship=Ship(ai_settings,screen)   #建立飛船
    bullets=Group()
    aliens=Group()
    gf.creat_fleet(ai_settings,screen,ship,aliens)

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        if stats.game_active:
            ship.update()
            gf.update_bullets(ai_settings,screen,ship,aliens,bullets)
            gf.update_aliens(ai_settings,stats,screen,ship,aliens,bullets)
        gf.update_screen(ai_settings,screen,ship,aliens,bullets)

run_game()

當把飛船次數用完後,螢幕到停止不動了: