游戲開發最核心的就是碰撞檢測了,子彈擊中敵人、足球射進門、吃加血包這些都是通過碰撞檢測完成的。我們這節課學習的sprite模塊對pygame的碰撞做了初步封裝,簡化我們開發這些模塊時的代碼。
在pygame里,sprite通常是一個二維的圖片。比如一輛汽車、一個狐貍、一條小狗等。下面我們就來詳細學習一下sprite模塊。

## prite基礎和碰撞檢測
讓我們來看一個使用sprite的例子,這個例子展示了一個紅豆吃黑豆的游戲,屏幕上的紅豆會跟著我們的鼠標移動,紅豆碰到黑豆后會把黑豆吃掉。游戲效果如下圖所示:

項目代碼可以訪問下面的鏈接:ProgramArcadeGames.com/python_examples/f.php?file=sprite_collect_blocks.py
下面我們就來詳細分析一下這個代碼。
```
import pygame
import random
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
```
首先,我們引入了pygame。并定義了黑、白、后三個顏色常量。
```
class Block(pygame.sprite.Sprite):
"""
This class represents the ball.
It derives from the "Sprite" class in Pygame.
"""
```
我們定義一個Block類,這個類繼承了:`pygame.sprite.Sprite`。因此,這個類具有了sprite類的所有屬性和方法。
```
def __init__(self, color, width, height):
""" Constructor. Pass in the color of the block,
and its x and y position. """
# Call the parent class (Sprite) constructor
super().__init__()
```
在Block類的init方法里,我們傳入了顏色、寬度、高度三個屬性。這里需要注意的是,我們通過`super().__init__()`調用了父類的初始化方法來初始化sprite的屬性。
```
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(color)
```
接下來,將sprite的image屬性設置為一個指定寬高的空圖片,并把它填充為指定的顏色。
這個類的整體初始化代碼如下:
```
def __init__(self, color, width, height):
"""
Ellipse Constructor. Pass in the color of the ellipse,
and its size
"""
# Call the parent class (Sprite) constructor
super().__init__()
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
# Draw the ellipse
pygame.draw.ellipse(self.image, color, [0, 0, width, height])
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
```
在這個構造方法里,一定要注意最后一行的`self.rect = self.image.get_rect()`來初始化sprite的rect屬性。rect屬性是pygame里Rect類的一個實例。這個矩形表示了sprite對象的二維邊界,Rect里有x,y兩個關鍵的可修改屬性。pygame會把sprite畫的屏幕的(x,y)上。所以,移動一個sprite就是更改sprite的rect.x,rect.y屬性。
```
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width, screen_height])
```
完成Block類的定義后,我們來初始化pygame。
```
# This is a list of 'sprites.' Each block in the program is
# added to this list.
# The list is managed by a class called 'Group.'
block_list = pygame.sprite.Group()
# This is a list of every sprite.
# All blocks and the player block as well.
all_sprites_list = pygame.sprite.Group()
```
使用sprites的主要好處是我們可以把游戲里的所有角色在一個組里做統一處理。巴塔木放大哦一個統一的組里后,我們可以同時渲染、移動他們。我們還可以檢測一個角色是否和組里的任何一個角色發生碰撞。
上面的代碼里我們定義了兩個group,`all_sprites_list`用來存儲所有的角色,這個組用來渲染游戲里的所有角色。`block_list `用來存儲游戲里的碰撞目標。
```
for i in range(50):
# This represents a block
block = Block(BLACK, 20, 15)
# Set a random location for the block
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(screen_height)
# Add the block to the list of objects
block_list.add(block)
all_sprites_list.add(block)
```
接下來,我們使用for循環來初始化黑色的塊,這里注意,我們我們使用random來講每個block隨機到窗口的不同位置上。然后,我們把所有黑色的塊放到`block_list`和`all_sprites_list`里。
```
# Create a RED player block
player = Block(RED, 20, 15)
all_sprites_list.add(player)
```
接下來,我們初始化紅色的塊。
```
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Clear the screen
screen.fill(WHITE)
```
角色初始化完成后,我們進入游戲的主循環。我們定義了一個score變量來存儲我們的游戲得分,同時,我們把屏幕設置為白色。
```
# Get the current mouse position. This returns the position
# as a list of two numbers.
pos = pygame.mouse.get_pos()
# Fetch the x and y out of the list,
# just like we'd fetch letters out of a string.
# Set the player object to the mouse location
player.rect.x = pos[0]
player.rect.y = pos[1]
```
我們使用`mouse.get_pos()`獲取鼠標位置對象,然后把player.rect的x y屬性設置為鼠標的橫縱坐標。
```
# See if the player block has collided with anything.
blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
```
移動完紅色塊后,我們使用`pygame.sprite.spritecollide`方法來檢查紅色塊是否和黑色塊發生碰撞。第一個參數傳入檢測對象,第二個參數傳入檢測目標。第三個參數代表了如果group里的元素和player碰撞后,是否移除這個元素。
```
# Check the list of collisions.
for block in blocks_hit_list:
score +=1
print(score)
```
獲取碰撞的塊后,我們使用for循環來增加得分,并打印得分。
```
# Draw all the spites
all_sprites_list.draw(screen)
```
碰撞檢測完成后,我們重新將所有角色渲染到screen上。group對象里有個draw方法,這個方法會循環group里的每個sprite,并調用sprite的draw方法。這樣,我們只需要使用一行代碼就可以將所有sprite渲染到screen上了。
```
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit()
```
最后,我們設置游戲幀率為60,調用display的flip方法來重新渲染整個屏幕。在主循環結束后,我們調用pygame的quit方法來結束游戲。
**阿達老師-孩子身邊的編程專家**
*完整課程請關注阿達老師,主頁里有完整的課程目錄和觀看地址*
- 課程介紹
- 搭建環境
- 什么是計算機
- 程序是怎么運行的
- 安裝python
- 項目實例-安裝IDE
- 變量和簡單數據類型
- 數據&變量
- 數字
- 字符串
- 布爾類型
- 項目實例
- 容器-列表
- 容器
- 列表
- 項目實例
- 容器-字典
- 定義字典
- 項目實例
- 數據類型總結
- 條件語句
- python條件語句
- 項目實例
- 循環語句
- for循環
- while循環
- 項目實例
- 函數
- 5.0函數定義
- 5.2函數實戰
- 6.文件系統
- 6.1 文件系統介紹&python查找文件
- 6.2 用python讀寫文件
- 7. python操作時間
- 8.面向對象
- 8.1 類和對象
- 8.2 繼承和重寫
- 8.3 面向對象項目實戰
- 9 GUI編程
- 9.1 GUI基礎
- 9.2 備忘清單GUI版
- 10.網絡
- 10.1 網絡的發展
- 10.2 python http
- 11.web開發
- 11.1 web基礎&HTML
- 11.2 CSS&JavaScript
- 11.3 網頁計算器
- 11.3 網站開發實戰-播客搭建
- 11.3 python-web
- 12. 項目實戰-數據處理
- 13. 項目實戰-AI入門
- 13.1 環境搭建
- 心得
- 13.2 Tensorflow的瓜怎么吃
- 14 pygame
- 14.1 pygame Helloworld
- 14.4 pygame 動畫基礎 Animation
- 從0開始學python第14.5節 pygame 加載圖片和聲音
- 從0開始學python第14.6節 pygame.sprite(上)
- 14.7 pygame.sprite模塊(下)
- 14.8 pygame射擊游戲(一)
- pygame射擊游戲(二)
- 14.8 pygame射擊游戲(三)
- 14.8 pygame射擊游戲(四)
- 14.8 pygame射擊游戲(五)