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

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

上一節已經完成了飛船的左右移動,這節來完成調節飛船移動的速度,以及射擊。


在上一張我們知道飛船每次移動1畫素,而且有時候會移動到螢幕之外。我們可以設定飛船移動速度,在Setting  類修改

#儲存外星人遊戲開發的設定
class Setting():
    def __init__(self):
        self.screen_width=600     #設定螢幕高度寬度,背景顏色
        self.screen_height=600
        self.bg_color=(230,230,230)
        self.ship_speed_factor=1.5   #設定飛船移動

設定移動速度為1.5.但在ship類中因為rect的centerx不能儲存小數值,所以建立一個center

#-*-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:        #根據移動標誌,來調整位置
			self.center+=self.ai_settings.ship_speed_factor      #更新飛船的center的值,不是rect
			
		if self.moving_left:
			self.center-=self.ai_settings.ship_speed_factor
		
		self.rect.centerx=self.center    #來更新rect物件
        

	def blitme(self):
		self.screen.blit(self.image,self.rect)  

 因為我們把速度設定放在setting類裡,所以在這裡就要有ai_settings的形參,用於傳送資訊,在主程式裡:

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

from setting import Setting
from ship import Ship
import game_functions as gf

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)   #建立飛船

    while True:
        gf.check_events(ship)
        ship.update()
        gf.update_screen(ai_settings,screen,ship)

run_game()

輸出時,速度比之前是快了。

再限制一下飛船的活動範圍,防止在遊戲螢幕外面,我們可以通過檢查self.center的值是否等於螢幕的邊緣值,就可以解決該問題。我們在修改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)  

再執行主程式,就會發現飛船就在在螢幕裡移動,不會在螢幕之外。

接下來再針對於射擊:

我們先編寫子彈的矩形,以及按鍵空格鍵傳送子彈,子彈向上傳送,直至上邊緣消失,建立一個bullet類。我們先在設定類添子彈設定:

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

設定子彈的速度,矩形的長寬以及顏色,

接下來就是建立子彈類:

#-*-coding:GBK-*-
#-*-coding:utf-8-*-
#設定子彈類
import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):   #一個對子彈管理的類,繼承Sprite類
	def __init__(self,ai_settings,screen,ship):
		super().__init__()
		self.screen=screen
		
		#在(0,0)建立一個表示子彈的矩形,在設定正確的位置
		self.rect=pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
		self.rect.centerx=ship.rect.centerx
		self.rect.top=ship.rect.top
		
		#儲存小數的子彈值
		self.y=float(self.rect.y)
		
		self.color=ai_settings.bullet_color
		self.speed_factor=ai_settings.bullet_speed_factor
		
	def update(self):             #向上移動
		self.y-=self.speed_factor
		self.rect.y=self.y
		
	def draw_bullet(self):   #繪製子彈
		pygame.draw.rect(self.screen,self.color,self.rect)
		

 匯入pygame,因為子彈不是基於影象的,所以就使用pygame.Rect類來從空白開始建立一個矩形,建立這個這個類的例項的時候,必提供矩形左上角的x.y座標以及矩形的長寬,我們在(0.0)建立這個矩形,接下來的兩行程式碼將它移到正確的位置,子彈的初始位置是取決於飛船的位置。

主程式如下:

在主程式裡創造一個編組,用於儲存所有的有效的子彈,用於管理髮射出去的子彈。這個編組是pygame.sprite.Group 的一個例項,類似於列表,它繪製子彈以及更新每個子彈的位置。

#-*-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()    

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

run_game()

功能模組:

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

import sys
import pygame
from bullet import Bullet

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:      #響應按空格鍵
		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,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()

	pygame.display.flip()

編組bullets傳遞給check_keydown_events(),按下空格鍵的時候,建立一顆新子彈,並使用方法add將其加入到編組bullets中,之後,bullets.sprites()返回一個列表,包含於編組裡的所有子彈,我們在遍歷列表,對所有的子彈呼叫draw_bullet()。

刪除已經消失的子彈:

子彈到達頂部消失,並不是因為說它不存在了,而是因為pygame無法在螢幕外繪製他們,他們的座標為負值,會一直消耗記憶體和處理能力。我們要將這些子彈刪除,怎麼刪除,我們可以 檢查子彈的座標位置,當bottom=0的時候就代表到達頂部。

主程式如下:

#-*-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()    

    while True:
        gf.check_events(ai_settings,screen,ship,bullets)
        ship.update()
        bullets.update()

       #刪除子彈
        for bullet in bullets.copy():
            if bullet.rect.bottom<=0:
               bullets.remove(bullet)
        print(len(bullets))      #列印長度。只是為了確認下有沒有消失,後面可以刪掉
 
        gf.update_screen(ai_settings,screen,ship,bullets)

run_game()

我們使用copy來產生一個bullets的副本,遍歷這個副本。

限制子彈數量:

在設定類修改程式:

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

接下來在功能模組來檢查子彈數:

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

import sys
import pygame
from bullet import Bullet

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:      #響應按空格鍵
                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,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()

	pygame.display.flip()

再執行主程式看看實際結果:

重構整個函式:

1.功能模組:

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

import sys
import pygame
from bullet import Bullet

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,bullets):   # 更新螢幕
	screen.fill(ai_settings.bg_color)
	for bullet in bullets.sprites():
		bullet.draw_bullet()
	ship.blitme()

	pygame.display.flip()

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

主程式如下:

#-*-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()    

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

run_game()