Pygame 教程(6):使用精灵
本章,你將學習如何使用 Pygame 中的精靈。
導航
上一章:監測游戲時間
文章目錄
- 導航
- 精靈
- Sprite
- Group
- 碰撞檢測函數
- 實例:彈球
- 創建精靈
- 使用精靈
- 完整代碼
- 結語(很重要!!)
精靈
當游戲對象變得繁多的時候,把所有游戲對象的處理存放在一個個函數中,雖然是一種可行的方法,但是會使代碼邏輯比較混亂,難以維護。這時,精靈(sprite) 應運而生。使用精靈,可以將游戲對象封裝到一個個類當中,以將處理游戲對象的邏輯與主代碼邏輯分離開,使代碼架構更加清晰明了。
Pygame 中,通過pygame.sprite模塊使用精靈。該模塊定義了Sprite類(用于定義精靈)和Group類(用于管理精靈的容器)以及一些繼承于這兩個類的拓展類和檢測精靈碰撞的函數。
下面將主要介紹Sprite和Group類,以及常用的檢測碰撞的函數。
Sprite
pygame.sprite.Sprite通常作為可見游戲對象的基類。構造函數Sprite(*groups) -> Sprite接受任意數量的Group容器以添加到這些容器中。
繼承它的子類需要為image和rect屬性賦值。image屬性是一個pygame.Surface對象,指定該游戲對象的圖像。rect屬性是一個pygame.Rect對象,用于指定該游戲對象的位置,也用于檢測精靈碰撞而使用。
Sprite類中定義的方法如下表(詳見官方文檔):
| update(*args, **kwargs) -> None | 用于控制精靈行為的方法,通常子類需要重寫該方法。當調用了Group.update方法時,組中的所有精靈都會被調用Sprite.update方法,如果在Group.update方法中傳入了參數,參數也將被傳入Sprite.update方法中。 |
| add(*groups) -> None | 任意數量的Group對象作為參數傳遞,精靈將被添加到尚未成為成員的組中。 |
| remove(*groups) -> None | 任意數量的Group對象作為參數傳遞,精靈將從它所在的組中移除。 |
| kill() -> None | 將精靈從所有包含它的組中移除,這并不會改變本身的狀態,之后也可以繼續使用該精靈。 |
| alive() -> bool | 判斷此精靈是否屬于1個或多個組。 |
| groups() -> group_list | 返回包含此精靈的Group對象的列表。 |
Group
pygame.sprite.Group類通常作為用于管理多個Sprite對象的容器。此類也可以被繼承以創建有更具體行為的容器。構造函數Group(*sprites) -> Group接受任意數量的Sprite對象作為參數以添加到容器中。Group類還支持以下標準的 Python 操作:
- in,判斷是否包含了某個精靈。
- len,獲取組中的精靈總數。
- bool,判斷組中是否包含任何精靈。
- iter,迭代組中所有的精靈。
Group類中定義的方法如下表(詳見官方文檔):
| sprites() -> sprite_list | 返回組中包含的所有精靈的列表。 |
| copy() -> Group | 創建該組的副本。 |
| add(*sprites) -> None | 向組中添加任意數量的精靈,只添加尚未成為改組成員的精靈。 |
| remove(*sprites) -> None | 從組中刪除任意數量的精靈。只刪除是該組成員的精靈。 |
| has(*sprites) -> bool | 判斷組中是否包含給定的所有精靈。 |
| update(*args, **kwargs) -> None | 對組中所有的精靈調用Sprite.update方法,被傳入Group.update方法的參數也將傳入Sprite.update方法中。 |
| draw(Surface) -> List[Rect] | 將組中包含的所有精靈繪制到給定的圖像上,使用每個精靈的image屬性作為源圖像,rect屬性作為位置。Group并不保存精靈的順序,所以繪制順序是任意的。 |
| clear(Surface_dest, background) -> None | 在給定的圖像上清除上次調用Group.draw方法所使用的精靈,通過在對應精靈的位置上進行填充來清除。參數background通常是一個Surface圖像,要求尺寸與目標圖像相同,但是也可以是一個回調函數,需要兩個參數:目標圖像和要清除的區域。 |
| clear(Surface_dest, background) -> None | 從組中移除所有的精靈。 |
碰撞檢測函數
sprite模塊中還定義了一些碰撞檢測函數。以下內容將介紹常用的函數(詳見官方文檔)。
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list:返回一個組中與一個精靈相交的所有的精靈的列表。布爾參數dokill指定是否將所有將組中所有碰撞的精靈刪除。可選的參數collided是一個回調函數,用于計算兩個精靈是否碰撞,它應該把兩個精靈作為參數,并返回一個布爾值,表明是否相撞。如果沒有傳遞collided參數,則所有精靈都要求有rect屬性,用于計算碰撞。collided可以傳入的 Pygame 內置函數有:collide_rect,collide_rect_ratio,collide_circle,collide_circle_ratio,collide_mask。
collide_rect(left, right) -> bool:使用pygame.Rect.collide_rect方法檢測兩個精靈之間的碰撞,要求兩個精靈都有rect屬性。
collide_rect_ratio(ratio) -> collided_callable:一個可調用的類,collide_rect函數的可縮放版本,初始化時傳入一個比率。
collide_circle(left, right) -> bool:通過檢測以精靈為中心的兩個圓是否重疊來檢測碰撞。如果精靈有radius屬性,將被用來創建圓,否則,將創建一個足夠大的圓完全包圍精靈的rect屬性。兩個精靈必須有rect屬性和可選的radius屬性。
collide_circle_ratio(ratio) -> collided_callable:一個可調用的類,collide_circle函數的可縮放版本,初始化時傳入一個比率。
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict:參數與spritecollide函數類似,找到所有在兩組之間發生碰撞的精靈。group1中的所有精靈將添加為返回字典的鍵,而每個鍵對應的值就是group2中與該精靈發生碰撞的精靈列表。
spritecollideany(sprite, group, collided = None) -> Sprite | None:簡單測試精靈是否與組中任何一個精靈相撞,如果有碰撞,將返回組中的一個精靈,否則,返回None。
實例:彈球
本實例將利用Sprite創建一個彈球引用程序。
請創建一個新的文件,命名為ball.py,并添加以下代碼:
import sysimport pygameclass BallGame:def __init__(self) -> None:self.screen = pygame.display.set_mode((600, 600))pygame.display.set_caption('Ball')def run(self):while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()pygame.display.flip()if __name__ == '__main__':game = BallGame()game.run()創建精靈
我們需要創建一個繼承于Sprite類的精靈類Ball,在BallGame之前添加如下代碼:
class Ball(pygame.sprite.Sprite):def __init__(self, screen_rect) -> None:super().__init__()self.image = pygame.Surface((20, 20))pygame.draw.circle(self.image, (255, 255, 255), (10, 10), 10)self.screen_rect = screen_rectself.rect = self.image.get_rect()self.rect.center = self.screen_rect.centerself.vel = (2, 1)def update(self):self.rect.x += self.vel[0]self.rect.y += self.vel[1]if self.rect.left < 0 or self.rect.right > self.screen_rect.width:self.vel = (-self.vel[0], self.vel[1])if self.rect.top < 0 or self.rect.bottom > self.screen_rect.height:self.vel = (self.vel[0], -self.vel[1])上述代碼中,Ball類繼承于Sprite類,以定義一個精靈,并且使用pygame.draw.circle函數在image上繪制了一個白色的圓,同時將rect定位到屏幕矩形的中心。
update方法中,更新了rect的位置,并防止球超出屏幕范圍。
使用精靈
更改BallGame類的方法,代碼如下:
class BallGame:def __init__(self) -> None:self.screen = pygame.display.set_mode((600, 600))pygame.display.set_caption('Ball')self.ball = Ball(self.screen.get_rect())def run(self):while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()self.screen.fill((0, 0, 0))self.ball.update()self.screen.blit(self.ball.image, self.ball.rect)pygame.display.flip()這里并沒有使用Group來組織精靈,是因為我們只使用了一個精靈,無需使用它。
完整代碼
import sysimport pygameclass Ball(pygame.sprite.Sprite):def __init__(self, screen_rect) -> None:super().__init__()self.image = pygame.Surface((20, 20))pygame.draw.circle(self.image, (255, 255, 255), (10, 10), 10)self.screen_rect = screen_rectself.rect = self.image.get_rect()self.rect.center = self.screen_rect.centerself.vel = (2, 1)def update(self):self.rect.x += self.vel[0]self.rect.y += self.vel[1]if self.rect.left < 0 or self.rect.right > self.screen_rect.width:self.vel = (-self.vel[0], self.vel[1])if self.rect.top < 0 or self.rect.bottom > self.screen_rect.height:self.vel = (self.vel[0], -self.vel[1])class BallGame:def __init__(self) -> None:self.screen = pygame.display.set_mode((600, 600))pygame.display.set_caption('Ball')self.ball = Ball(self.screen.get_rect())def run(self):while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()self.screen.fill((0, 0, 0))self.ball.update()self.screen.blit(self.ball.image, self.ball.rect)pygame.display.flip()if __name__ == '__main__':game = BallGame()game.run()代碼運行截圖:
結語(很重要!!)
至此,Pygame 教程已經結束啦🎉🎉!!!通過此教程,你已經學會了 Pygame 的基礎知識。你已經可以嘗試自己編寫簡單的應用了。筆者也會努力更新,爭取寫出更多好的作品。
總結
以上是生活随笔為你收集整理的Pygame 教程(6):使用精灵的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [太原理工大学] 2023 信息安全技术
- 下一篇: ALP300智能型低压马达保护器