从0开始学python第14.6节 pygame.sprite(上)

游戏开发最核心的就是碰撞检测了,子弹击中敌人、足球射进门、吃加血包这些都是通过碰撞检测完成的。我们这节课学习的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_listall_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方法来结束游戏。

阿达老师-孩子身边的编程专家

完整课程请关注阿达老师,主页里有完整的课程目录和观看地址


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,348评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,122评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,936评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,427评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,467评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,785评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,931评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,696评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,141评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,483评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,625评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,291评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,892评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,492评论 2 348

推荐阅读更多精彩内容