本系列博客介紹以python+pygame庫進行小游戲的開發。有寫的不對之處還望各位海涵。
直到現在我們已經學了很多pygame基礎知識了,從這篇博客開始我們將會學習pygame中高級部分,更多和精靈模塊,沖突檢測相關的知識。
一、Sprite模塊、sprite對象
在pygame.sprite模塊里面包含了一個名為Sprite類,他是pygame本身自帶的一個精靈。但是這個類的功能比較少,因此我們新建一個類對其繼承,在sprite類的基礎上豐富,以方便我們的使用。
首先來了解一下如何使用sprite類來加載動畫吧。
1、精靈序列圖
將要加載的動畫幀放在一個精靈序列圖里面,然后在程序里面調用它。pygame會自動更新動畫幀,這樣一個動態的圖像就會展現在我們面前了。
下面是一個典型的精靈序列圖:行和列的索引都是從0開始的。
2、加載精靈圖序列:
在加載一個精靈圖序列的時候,我們需要告知程序一幀的大小,(傳入幀的寬度和高度,文件名)。
除此之外,還需要告訴精靈類,精靈序列圖里面有多少列。load函數可以加載一個精靈序列圖。
def load(self, filename, width, height, columns): self.master_image = pygame.image.load(filename).convert_alpha() self.frame_width = width self.frame_height = height self.rect = 0,0,width,height self.columns = columns
3.更新幀
一個循環動畫通常是這樣工作的:從第一幀不斷的加載直到最后一幀,然后在折返回第一幀,並不斷重復這個操作。
self.frame += 1 if self.frame > self.last_frame: self.frame = self.first_frame self.last_time = current_time
但是如果只是這樣做的話,程序會一股腦地將動畫播放完了,我們想讓它根據時間間隔一張一張的播放,因此加入定時的代碼。
pygame中的time模塊有一個get_ticks()方法可以滿足定時的需要。
ticks = pygame.time.get_ticks()
然后將ticks變量傳遞給sprite的update函數,這樣就可以輕松讓動畫按照幀速率來播放了。哦,幀速率還沒有設置,咱們現在設置一下幀速率。
啟動一個定時器,然后調用tick(num)函數就可以讓游戲以num幀來運行了。
framerate = pygame.time.Clock()
framerate.tick(60)
4、繪制幀
sprite.draw()方法是用來繪制幀的,但是這個函數是由精靈來自動調用的,我們沒有辦法重寫它,因此需要在update函數里面做一些工作。
首先需要計算單個幀左上角的x,y位置值(x表示列編號,y表示行編號):
frame_x = (self.frame % self.columns) * self.frame_width
#用幀數目除以行數,然后在乘上幀的高度
frame_y = (self.frame // self.columns) * self.frame_height
然后將計算好的x,y值傳遞給位置rect屬性。
frame_x = (self.frame % self.columns) * self.frame_width frame_y = (self.frame // self.columns) * self.frame_height rect = ( frame_x, frame_y, self.frame_width, self.frame_height ) self.image = self.master_image.subsurface(rect)
5、精靈組
當程序中有大量的實體的時候,操作這些實體將會是一件相當麻煩的事,那么有沒有什么容器可以將這些精靈放在一起統一管理呢?答案就是精靈組。
pygame使用精靈組來管理精靈的繪制和更新,精靈組是一個簡單的容器。
使用pygame.sprite.Group()函數可以創建一個精靈組:
group = pygame.sprite.Group()
group.add(sprite_one)
精靈組也有update和draw函數:
group.update()
group.draw()
二、自定義的精靈類
好了,通過前面的學習,我們已經了解了一些精靈的知識了,現在我們將前面說到的方法封裝成一個自定義的類,以方便我們的調用,這個類繼承自pygame.sprite.Sprite:
1 class MySprite(pygame.sprite.Sprite): 2 def __init__(self, target): 3 pygame.sprite.Sprite.__init__(self) #基類的init方法 4 self.target_surface = target 5 self.image = None 6 self.master_image = None 7 self.rect = None 8 self.topleft = 0,0 9 self.frame = 0 10 self.old_frame = -1 11 self.frame_width = 1 12 self.frame_height = 1 13 self.first_frame = 0 14 self.last_frame = 0 15 self.columns = 1 16 self.last_time = 0 17 18 def load(self, filename, width, height, columns): 19 self.master_image = pygame.image.load(filename).convert_alpha() 20 self.frame_width = width 21 self.frame_height = height 22 self.rect = 0,0,width,height 23 self.columns = columns 25 rect = self.master_image.get_rect() 26 self.last_frame = (rect.width // width) * (rect.height // height) - 1 27 28 def update(self, current_time, rate=60): 29 #更新動畫幀 30 if current_time > self.last_time + rate: 31 self.frame += 1 32 if self.frame > self.last_frame: 33 self.frame = self.first_frame 34 self.last_time = current_time 35 37 if self.frame != self.old_frame: 38 frame_x = (self.frame % self.columns) * self.frame_width 39 frame_y = (self.frame // self.columns) * self.frame_height 40 rect = ( frame_x, frame_y, self.frame_width, self.frame_height ) 41 self.image = self.master_image.subsurface(rect) 42 self.old_frame = self.frame
好了現在我們寫一個小程序來測試一下這個類的性能怎么樣。
這里我用ps制作了一個簡單的精靈序列圖,咱們就用這個萌萌的嗷大喵好了:
代碼:
import pygame from pygame.locals import * class MySprite(pygame.sprite.Sprite): def __init__(self, target): pygame.sprite.Sprite.__init__(self) self.target_surface = target self.image = None self.master_image = None self.rect = None self.topleft = 0,0 self.frame = 0 self.old_frame = -1 self.frame_width = 1 self.frame_height = 1 self.first_frame = 0 self.last_frame = 0 self.columns = 1 self.last_time = 0 def load(self, filename, width, height, columns): self.master_image = pygame.image.load(filename).convert_alpha() self.frame_width = width self.frame_height = height self.rect = 0,0,width,height self.columns = columns rect = self.master_image.get_rect() self.last_frame = (rect.width // width) * (rect.height // height) - 1 def update(self, current_time, rate=60): if current_time > self.last_time + rate: self.frame += 1 if self.frame > self.last_frame: self.frame = self.first_frame self.last_time = current_time if self.frame != self.old_frame: frame_x = (self.frame % self.columns) * self.frame_width frame_y = (self.frame // self.columns) * self.frame_height rect = ( frame_x, frame_y, self.frame_width, self.frame_height ) self.image = self.master_image.subsurface(rect) self.old_frame = self.frame pygame.init() screen = pygame.display.set_mode((800,600),0,32) pygame.display.set_caption("精靈類測試") font = pygame.font.Font(None, 18) framerate = pygame.time.Clock() cat = MySprite(screen) cat.load("sprite.png", 100, 100, 4) group = pygame.sprite.Group() group.add(cat) while True: framerate.tick(30) ticks = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit() key = pygame.key.get_pressed() if key[pygame.K_ESCAPE]: exit() screen.fill((0,0,100)) group.update(ticks) group.draw(screen) pygame.display.update()
效果圖:萌萌的嗷大喵躍然於屏幕上。看起來功能還不錯的說。
大家也可以制作一些自己喜歡的精靈序列圖,然后加載並查看他們的效果。
關於精靈與精靈之間的沖突檢測,精靈與組之間的碰撞檢測,我們將會放在下個博客一起學習。