前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pygame-KidsCanCode系列jumpy-part0-使用sprite

pygame-KidsCanCode系列jumpy-part0-使用sprite

作者头像
菩提树下的杨过
发布2019-09-12 11:18:56
5480
发布2019-09-12 11:18:56
举报

本篇主要是sprite的入门使用:

pygame开发,有一个所谓的最小框架(或称为模板),大概长下面这个样子:

代码语言:javascript
复制
import pygame
import time

# 游戏中的一些常量定义
SIZE = WIDTH, HEIGHT = 300, 100
FPS = 10

# 颜色常量定义
BLACK = 0, 0, 0
WHITE = 255, 255, 255

# 初始化
pygame.init()
pygame.mixer.init()

# 窗口、标题等初始化
screen = pygame.display.set_mode(SIZE)
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()

# 循环入口
running = True
while running:

    # 设置帧数
    clock.tick(FPS)

    # 事件处理
    for event in pygame.event.get():
        # 退出处理
        if event.type == pygame.QUIT:
            running = False

    # (update) 游戏更新逻辑(比如:改动角色的位置或一些重要变量等,这里仅演示更新当前时间)
    font = pygame.font.SysFont('Menlo', 25, True)
    current_time = font.render(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())), 1, WHITE)

    # (draw)渲染屏幕
    screen.fill(BLACK)  # 先准备一块黑布
    screen.blit(current_time, current_time.get_rect(center=(WIDTH / 2, HEIGHT / 2)))  # 把时间显示在画布中央

    # 屏幕内容刷新
    pygame.display.update()

# 循环结束后,退出游戏
pygame.quit()

开发新游戏时,把上面这个模板复制一份新的,然后改改里面update/draw这二个部分即可。为了方便新同学理解"模板"的处理流程,从视频中截了二张图:

可以有同学注意到了,代码头部有很多常量定义,按模块化的思想,可以把这些常量定义单独提取出来,放到一个settings.py文件里,以后修改起来会比较方便。

代码语言:javascript
复制
SIZE = WIDTH, HEIGHT = 480, 320
FPS = 30

TITLE = "sprite sample"

# define color
BLACK = 0, 0, 0
WHITE = 255, 255, 255
RED = 255, 0, 0
GREEN = 0, 255, 0
BLUE = 0, 0, 255

# define player bound
PLAYER_TOP_LIMIT = 100
PLAYER_BOTTOM_LIMIT = 250

把刚才的模板,拷一份新的出来,引用这个settings.py,同时把我们的主角Sprite也加进来

代码语言:javascript
复制
import pygame
from part_00.settings import *

pygame.init()
pygame.mixer.init()

screen = pygame.display.set_mode(SIZE)
pygame.display.set_caption(TITLE)
clock = pygame.time.Clock()


# 定义游戏主角类
class Player(pygame.sprite.Sprite):
    def __init__(self):
        # 第1行,必须调用Sprite父类的构造函数
        pygame.sprite.Sprite.__init__(self)
        # 注意:sprite必须指定image, rect这二个属性
        self.image = pygame.Surface((20, 20))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.center = WIDTH / 2, HEIGHT / 2

    # 更新逻辑
    def update(self):
        self.rect.x += 5
        if self.rect.left > WIDTH:
            self.rect.right = 0


# 这里要有一个类似分组(或容器)的东西,存放所有游戏中的sprite实例
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

running = True
while running:

    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # update
    all_sprites.update()

    # draw /render
    screen.fill(BLACK)
    all_sprites.draw(screen)  # 绘制所有sprite

    pygame.display.update()

pygame.quit()

注1:第2行导入的写法,留意一下,主要是目录的指定,参考下图的目录结构

注2:pygame.sprite.Sprite这个类,如果查看源码,有一段英文说明

代码语言:javascript
复制
class Sprite(object):
    """simple base class for visible game objects

    pygame.sprite.Sprite(*groups): return Sprite

    The base class for visible game objects. Derived classes will want to
    override the Sprite.update() method and assign Sprite.image and Sprite.rect
    attributes.  The initializer can accept any number of Group instances that
    the Sprite will become a member of.

    When subclassing the Sprite class, be sure to call the base initializer
    before adding the Sprite to Groups.

    """
   ...

大意是说,如果子类继承自Sprite类,可以重写update(),同时可以指定image、rect属性,最后__init__初始化(构造函数)首行,必须调用父类的__init__方法。

我们自定义了一个Player的Sprite,同时在update()方法中,做了一些逻辑处理,主要是让rect对象每帧横向向右移动5px,同时加入了边界检测,如果向右跑出窗口区域,则把它放到左侧,继续运动(视觉上看,感觉运动是连贯的)。

注: 让对象移动的方法有N种,要点无非就是改变对象外切矩形Rect的某个属性,Rect对象提供了N多与位置(及大小)相关的属性,几乎是想你所想:

代码语言:javascript
复制
bottom = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

bottomleft = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

bottomright = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

center = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

centerx = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

centery = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

h = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

height = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

left = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

midbottom = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

midleft = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

midright = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

midtop = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

right = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

size = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

top = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

topleft = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

topright = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

w = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

width = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

x = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

y = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default

关于Sprite以及Sprite的Group,有几个重要的属性:

Sprite.kill() --字面上讲,就是杀死精灵,调用该方法后,如果这个sprite加入了多个group,将同步把自己从所有group中移除。 

Group.spritecollide() --即:精灵之间的碰撞检测,pygame已经封装好了,不用开发人员再去伤脑筋了(后面我们会大量使用该方法)

代码语言:javascript
复制
def spritecollide(sprite, group, dokill, collided=None):
    """find Sprites in a Group that intersect another Sprite

    pygame.sprite.spritecollide(sprite, group, dokill, collided=None):
        return Sprite_list

    Return a list containing all Sprites in a Group that intersect with another
    Sprite. Intersection is determined by comparing the Sprite.rect attribute
    of each Sprite.

    The dokill argument is a bool. If set to True, all Sprites that collide
    will be removed from the Group.

    The collided argument is a callback function used to calculate if two
    sprites are colliding. it should take two sprites as values, and return a
    bool value indicating if they are colliding. If collided is not passed, all
    sprites must have a "rect" value, which is a rectangle of the sprite area,
    which will be used to calculate the collision.

这是该方法的说明,大意是说,返回值是一个列表,里面包含了发生碰撞的所有sprite的Rect对象;另外doKill参数,如果指定为True,则表示将发生碰撞的sprite杀死;最后一个collided可以指定回调方法。

刚才的代码,运动起来后,效果如下:

如果觉得一个小方块,比较枯燥,可以换一个图片,推荐一个网站:https://opengameart.org/ 上面有大量的免费游戏素材,随便挑几张图片:

代码如下:

代码语言:javascript
复制
import pygame
from part_00.settings import *
import os

pygame.init()
pygame.mixer.init()

screen = pygame.display.set_mode(SIZE)
pygame.display.set_caption(TITLE)
clock = pygame.time.Clock()

game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "../img/")


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(img_folder, "p1_jump.png"))
        # 如果图片显示时,发现不透明(看具体操作系统),可以加下面这行
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.center = WIDTH / 2, HEIGHT / 2
        self.y_speed = 5

    def update(self):
        self.rect.x += 5
        self.rect.y += self.y_speed

        # 边界检测
        if self.rect.left > WIDTH:
            self.rect.right = 0
        if self.rect.top < PLAYER_TOP_LIMIT:
            self.y_speed = -self.y_speed
        if self.rect.bottom > PLAYER_BOTTOM_LIMIT:
            self.y_speed = -self.y_speed


all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

running = True
while running:

    clock.tick(FPS)

    # process input (events)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    all_sprites.update()

    # draw /render
    screen.fill(BLACK)
    pygame.draw.line(screen, GREEN, (0, PLAYER_TOP_LIMIT), (WIDTH, PLAYER_TOP_LIMIT), 1)
    pygame.draw.line(screen, GREEN, (0, PLAYER_BOTTOM_LIMIT), (WIDTH, PLAYER_BOTTOM_LIMIT), 1)
    all_sprites.draw(screen)

    pygame.display.update()

pygame.quit()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-01-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档