游戏开发最核心的就是碰撞检测了,子弹击中敌人、足球射进门、吃加血包这些都是通过碰撞检测完成的。我们这节课学习的sprite模块对pygame的碰撞做了初步封装,简化我们开发这些模块时的代码。
在pygame里,sprite通常是一个二维的图片。比如一辆汽车、一个狐狸、一条小狗等。下面我们就来详细学习一下sprite模块。
![](http://www.hoogge.com/down368/allimg/160821/1_160821154805_1.jpg)
## prite基础和碰撞检测
让我们来看一个使用sprite的例子,这个例子展示了一个红豆吃黑豆的游戏,屏幕上的红豆会跟着我们的鼠标移动,红豆碰到黑豆后会把黑豆吃掉。游戏效果如下图所示:
![](https://adatech-1256165843.cos.ap-chengdu.myqcloud.com/20181016220754.png)
项目代码可以访问下面的链接: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射击游戏(五)