URLhttps://learnscript.net/zh/pygame/surface/draw/
    复制链接转到说明  示例

    如何绘制表面(图像,字体)?以及颜色混合模式,剪辑区域,锁定等问题

    我被代码海扁署名-非商业-禁演绎
    阅读 17:02·字数 5113·发布 

    Pygame 中的颜色混合模式

    在 Pygame 中,如果Surface对象支持透明度,那么在绘制拥有透明度的颜色时,混合模式将决定颜色的显示效果,即被绘制的颜色如何与相同位置的原有颜色进行计算。如果原有颜色没有透明度或者表面对象不支持透明度,那么即便设置了混合模式也不会生效。

    pygame模块提供了以下变量,可用于在函数或方法中设置颜色的混合模式,BLEND_ADDBLEND_SUBBLEND_MULTBLEND_MINBLEND_MAXBLEND_RGBA_ADDBLEND_RGBA_SUBBLEND_RGBA_MULTBLEND_RGBA_MINBLEND_RGBA_MAXBLEND_RGB_ADDBLEND_RGB_SUBBLEND_RGB_MULTBLEND_RGB_MINBLEND_RGB_MAXBLEND_PREMULTIPLIEDBLEND_ALPHA_SDL2

    为表面填充颜色

    Surface对象的fill方法,可用于为游戏表面的指定区域填充某种颜色,并指定混合模式。

    fill(color, rect, special_flags)

    color 参数

    color参数是一个包含颜色信息的对象,该对象的书写格式与Color对象的构造器的rgbvalue参数类似。

    rect 参数

    rect参数是一个包含矩形信息的对象,决定了表面对象的一些特性,该对象的书写格式与Rect对象的构造器的single_arg参数类似。

    special_flags 参数

    special_flags参数是颜色的混合模式,你可以查看颜色混合模式一段来了解更多。

    颜色,矩形

    关于Color构造器的rgbvalue参数,你可以查看Pygame 中的 Color 对象一段。关于Rect构造器的single_arg参数,你可以查看Pygame 中的 Rect 对象一段。

    在下面的示例中,我们绘制了两个矩形,其中一个透明,另一个不透明,他们有部分区域是重叠的,混合模式为颜色相加。

    fill.py
    from pygame import Surface, SRCALPHA, BLEND_RGBA_ADD
    
    # 创建支持透明度的表面,并设置表面的透明度 s = Surface((800, 600), SRCALPHA) # 绘制一个不透明矩形 s.fill('#ff0000', [100, 100, 100, 100]) # 绘制一个透明矩形,与不透明矩形部分重叠 s.fill('#ffff0099', [150, 150, 100, 100], BLEND_RGBA_ADD)
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)

    在表面中绘制表面

    Surface对象的blit方法,可用于在游戏表面中绘制另一个表面。

    blit(source, dest, area=None, special_flags=0)

    source 参数

    source参数是需要被绘制的表面对象。

    dest 参数

    dest参数表示了绘制的开始位置,他可以是依次包含 X 坐标和 Y 坐标的 Python 浮点数序列对象,或者是包含矩形信息的对象(书写格式与Rect对象的构造器的single_arg参数类似),矩形的左上角坐标即为绘制的开始位置(矩形的大小不会起到任何作用)。

    area 参数

    area参数是一个包含矩形信息的对象,用于指定绘制source参数所表示的表面的哪个区域,该对象的书写格式与Rect对象的构造器的single_arg参数类似。

    special_flags 参数

    special_flags参数是颜色的混合模式,你可以查看颜色混合模式一段来了解更多。

    返回值

    blit方法的返回值是一个Rect对象,表示目标表面中被实际绘制了内容的区域,该区域不会超出表面的剪辑区域。

    Surface对象的blits方法,可用于在游戏表面中绘制多个其他表面。

    blits(blit_sequence, doreturn=1)

    blit_sequence 参数

    blit_sequence参数是一个包含若干元组的 Python 序列对象,每一个元组的形式均类似于(source,dest,area,special_flags),其中的sourcedestareaspecial_flags的含义和书写格式与blit方法的sourcedestareaspecial_flags参数相同。

    你可以省略元组中的元素areaspecial_flags,因此,元组的形式也可以类似于(source,dest)(source,dest,area)(source,dest,special_flags)

    doreturn 参数

    如果doreturn参数等价于True,那么blits方法将返回实际绘制区域,否则将返回None

    返回值

    blits方法的返回值是None或一个包含若干Rect对象的 Python 列表,Rect对象表示目标表面中被实际绘制了内容的区域,该区域不会超出表面的剪辑区域。

    颜色深度为 8 的 Pygame Surface 对象不支持颜色的透明度

    如果Surface对象的颜色深度为 8,那么表面将不支持颜色的透明度,source参数所表示的表面中的颜色的透明度将被忽略。

    blit.py
    from pygame import Surface
    
    # 创建一些表面对象 s1 = Surface([100, 100]) s1.fill(0xff0000, [0, 0, 100, 100]) s2 = Surface([50, 50]) s2.fill('green', [0, 0, 50, 50]) s3 = Surface([100, 100]) s3.fill('#0000ff', [0, 0, 100, 100])
    # 创建游戏窗口并绘制多个表面 from pygame import display w = display.set_mode((800, 600)) w.blits([ (s1, (0, 0)), (s2, (100, 0)), # 只绘制 s3 的左上角区域 (s3, (150, 0), [0, 0, 25, 25]) ]) display.flip()
    # 等待 3 秒钟 import time time.sleep(3)

    转换表面的像素格式

    如果一个表面对象需要被多次的绘制,那么可以事先转换像素格式,使其与需要绘制到的表面的像素格式相同。

    Surface对象的convert方法,将根据给出的像素格式创建一个新的不支持透明度的表面,如果没有给出任何参数,则采用游戏窗口对应的表面的像素格式。

    convert()
    convert(surface)
    convert(depth, flags=0)
    convert(masks, flags=0)

    surface 参数

    surface参数是一个表面对象,将采用该表面对象的像素格式。

    depth,flags,masks 参数

    参数depthflagsmasks,与Surface对象的构造器的同名参数的作用和书写格式相同,分别表示表面的颜色深度,特性,以及用于颜色映射整数的掩码。

    返回值

    convert方法的返回值是一个已经转换了像素格式的新的Surface对象。

    convert方法类似,Surface对象的convert_alpha方法同样会根据给出的像素格式创建一个新的表面,只不过该表面支持透明度。

    convert_alpha()
    convert_alpha(surface)

    surface 参数

    surface参数是一个表面对象,将采用该表面对象的像素格式。

    返回值

    convert_alpha方法的返回值是一个已经转换了像素格式的新的Surface对象。

    表面

    关于Surface构造器的相关参数,你可以查看Pygame 中的 Surface 对象一段。

    在下面的示例中,虽然使用了变量SRCALPHA,但表面对象cs并不支持透明度,因此,第一个红色正方形没有透明效果。

    convert.py
    # 导入并创建游戏窗口
    from pygame import display, Surface, SRCALPHA
    w = display.set_mode((800, 600))
    
    # 创建支持透明度的表面对象,填充具有透明度的红色正方形 s = Surface([100, 100], SRCALPHA) s.fill('#ff000099', [0, 0, 100, 100])
    # 转换像素格式,新表面不支持透明度 cs = s.convert(16, SRCALPHA) print(f'cs 特性:{cs.get_flags()}') # 转换像素格式,新表面支持透明度 cas = s.convert_alpha() print(f'cas 特性:{cas.get_flags()}')
    # 在游戏窗口中绘制 cs 和 cas w.blit(cs, (0, 0)) w.blit(cas, (100, 100)) display.flip()
    import time time.sleep(3)

    在表面中绘制图像和文本(字体)

    事实上,在 Pygame 中无论是图像还是文本,最终只能以Surface表面对象的形式被绘制。对于图像,在使用image模块加载图像文件后,你将获得已经绘制了图像的表面对象,对于文本,你需要首先创建Font对象,然后使用字体对象的render方法,将指定的文本转换为一个表面对象。

    render(text, antialias, color, background=None)

    text 参数

    text参数是包含了需要绘制的文本的字符串。

    antialias 参数

    如果antialias参数等价于True,那么被绘制的文本将拥有抗锯齿效果。

    color 参数

    color参数表示文本的颜色,其书写格式与Color对象的构造器的rgbvalue参数类似。

    background 参数

    background参数表示文本的背景颜色(默认为None,背景透明),其书写格式与Color对象的构造器的rgbvalue参数类似。

    返回值

    render方法的返回值是绘制了文本的Surface对象。

    Font 对象的 render 方法不会处理字符串中的转义序列

    Font对象的render方法不会处理字符串中的转义序列,比如,换行符\n和制表符\t,他们可能会被表示为一个或数个空心方块,这意味着要绘制多行文本可能需要多次调用render方法。

    font_image.py
    # 导入模块并进行初始化
    from pygame import font, image
    font.init()
    
    # 使用 Pygame 默认字体绘制文本 Hello f = font.Font(size=30) ts = f.render('Hello', True, [2, 255, 0], '#ffffff')
    # 加载图像文件 img = image.load('candy.png')
    # 创建游戏窗口并绘制 ts 和 img from pygame import display w = display.set_mode([800, 600]) w.blit(ts, (50, 50)) w.blit(img, (100, 100)) display.flip()
    import time time.sleep(3)

    获取和设置表面的剪辑区域

    每一个 Pygame 的表面对象都拥有一个剪辑区域,位于剪辑区域以外的像素是不可修改的,默认情况下,剪辑区域等同于表面自身,这表示你可以为表面中的任意像素设置颜色。

    Surface对象的get_clip方法,可用于获取表面对象的剪辑区域。

    get_clip()

    返回值

    get_clip方法的返回值是表示表面剪辑区域的Rect对象。

    Surface对象的set_clip方法,可用于设置表面对象的剪辑区域。

    set_clip(rect)

    rect 参数

    rect参数是一个包含矩形信息的对象,该对象用于指定表面的剪辑区域,其书写格式与Rect对象的构造器的single_arg参数类似。

    如果rect参数为None,那么剪辑区域将等同于表面自身。

    在下面的示例中,白色的正方形被设置为了表面的剪辑区域,而之后绘制的绿色正方形并没有全部显示,因为他的一部分在剪辑区域之外,当我们重新将剪辑区域设置为表面自身后,蓝色正方形被完整的绘制。

    clip.py
    from pygame import Surface
    
    s = Surface([800, 600]) # 绘制一个白色的正方形并将其设置为剪辑区域 s.fill('white', ((100, 100), (100, 100))) s.set_clip((100, 100), (100, 100)) print(f'当前剪辑区域:{s.get_clip()}')
    # 绘制一个与白色正方形部分重叠的绿色正方形 s.fill('#00ff00', (150, 150, 100, 100))
    # 将整个表面设置为剪辑区域 s.set_clip(None) print(f'当前剪辑区域:{s.get_clip()}')
    # 绘制一个与白色正方形部分重叠的蓝色正方形 s.fill('#0000ff', [50, 50, 100, 100])
    # 创建游戏窗口并绘制 s from pygame import display w = display.set_mode((800, 600)) w.blit(s, (0, 0)) display.flip()
    import time time.sleep(3)
    当前剪辑区域:<rect(100, 100, 100, 100)>
    当前剪辑区域:<rect(0, 0, 800, 600)>

    Surface 对象的剪辑区域不会超出表面自身表示的范围

    set_clip方法的rect参数指示一个超出表面自身范围的剪辑区域时,该剪辑区域将被调整(超出表面自身范围的区域将不被考虑),以使其完全处于表面所表示的范围之内。

    clip_outside.py
    from pygame import Surface
    
    s = Surface([100, 100]) # 剪辑区域超出了表面的大小 s.set_clip((0, 0, 110, 120)) print(f'当前剪辑区域:{s.get_clip()}')
    当前剪辑区域:<rect(0, 0, 100, 100)>

    锁定和解锁表面

    Surface对象的lockunlock方法,可用于锁定和解锁表面。当一个表面被锁定时,Pygame 将不能对其进行绘制和管理,这意味着该表面无法显示在游戏中,除非他被解锁,正因如此,你不应该让一个Surface对象长时间处于锁定状态。

    lock()
    unlock()

    Surface对象的mustlock方法,可用于判断是否必须锁定表面,在访问与表面像素相关的数据之前,该方法几乎不会被使用,因为 Pygame 会自行管理表面的锁定和解锁。

    mustlock()

    返回值

    如果mustlock方法返回True,那么表示表面需要锁定。

    Surface对象的get_locked方法,可用于判断表面是否已经被锁定。

    get_locked()

    返回值

    如果get_locked方法返回True,那么表示表面已经被锁定。

    Surface对象的get_locks方法,可用于获取已经被锁定的表面,通常是指表面自身,但也可能是该表面的子表面。

    get_locks()

    返回值

    get_locks方法返回一个 Python 元组,元组中包含了被锁定的表面对象。这里需要说明的是,如果你多次调用Surface对象的lock方法,那么Surface对象可能会重复出现在元组中。

    Surface 对象通常被自动锁定或解锁

    当需要对游戏表面进行某种读取或写入时,一些方法或函数将自动锁定或解锁Surface表面对象,因此,需要主动调用lock方法的情况并不多,除非有大量锁定和解锁表面的操作,比如,对表面中的每个像素逐一进行读取或修改。

    在下面的示例中,由于我们锁定了表面对象s1,因此,将其绘制到表面对象s2会引发异常pygame.error: Surfaces must not be locked during blit

    lock.py
    from pygame import Surface
    
    s1 = Surface([800, 600]) s1.fill('white', [0, 0, 100, 100]) print(f'是否需要锁定:{s1.mustlock()}') # 锁定表面两次 s1.lock() s1.lock() print(f'是否已经锁定:{s1.get_locked()}') print(f'已经存在的锁:{s1.get_locks()}')
    s2 = Surface([800, 600]) # ERROR 无法绘制被锁定的表面 s2.blit(s1, [0, 0])
    pygame.error: Surfaces must not be locked during blit

    源码

    src/zh/surface/draw·codebeatme/pygame·GitHub

    讲解视频

    如何在 Pygame 中绘制表面·YouTube如何在 Pygame 中绘制表面·Bilibili
    如何在 Pygame 中绘制图像和文本·YouTube如何在 Pygame 中绘制图像和文本·Bilibili
    如何在 Pygame 中转换像素格式,提高渲染效率·YouTube如何在 Pygame 中转换像素格式,提高渲染效率·Bilibili