在不覆盖透明度的情况下更改表面的颜色 [英] Changing colour of a surface without overwriting transparency

查看:76
本文介绍了在不覆盖透明度的情况下更改表面的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在运行时动态更改矩形的颜色.目前 set_colour 正在用单一颜色值填充表面的所有像素.这是可行的,但是当调用 set_outline 之类的方法时会出现问题,该方法会修改表面的透明度.

class Rectangle(pg.sprite.Sprite):def __init__(self):pg.sprite.Sprite.__init__(self)self.original_image = pg.Surface((10, 10))self.image = self.original_imageself.rect = self.image.get_rect()def set_colour(self, colour_value):self.color = colour_valueself.image.fill(self.color)self.original_image.fill(self.colour)def set_outline(自我,厚度):self.thickness = 厚度大小 = self.image.get_size()计算 = 厚度/100p_width, p_height = 大小[0], 大小[1]宽度,高度 = 尺寸[0]*计算,尺寸[1]*计算self.image = self.image.convert_alpha()center_x, center_y = (p_width//2)-(width//2), (p_height//2)-(height//2)pg.draw.rect(self.image, (0, 0, 0, 0), (center_x, center_y, width, height))

现在,如果我尝试在运行时更改该矩形的颜色,它将覆盖在 set_outline 中创建的所有透明像素.

有没有办法将颜色遮罩或混合到矩形上,这样它就不会取代任何透明度?

解决方案

您可以通过 2 个步骤来实现.self.original_image 包含具有所需颜色的填充矩形:

<块引用>

self.original_image.fill(self.colour)

生成一个完全白色的矩形和透明区域.将矩形与 (self.image) 和混合模式 BLEND_MAX 混合(参见

将pygame导入为pg类矩形(pg.sprite.Sprite):def __init__(self):pg.sprite.Sprite.__init__(self)self.original_image = pg.Surface((150, 150))self.image = self.original_imageself.rect = self.image.get_rect(center = (150, 150))def set_colour(self, colour_value):self.color = colour_valueself.original_image.fill(self.colour)whiteTransparent = pg.Surface(self.image.get_size(), pg.SRCALPHA)whiteTransparent.fill((255, 255, 255, 0))self.image.blit(whiteTransparent, (0, 0), special_flags=pg.BLEND_MAX)self.image.blit(self.original_image, (0, 0), special_flags=pg.BLEND_MULT)def set_outline(自我,厚度):self.thickness = 厚度大小 = self.image.get_size()计算 = 厚度/100p_width, p_height = 大小[0], 大小[1]宽度,高度 = 尺寸[0]*计算,尺寸[1]*计算self.image = self.image.convert_alpha()center_x, center_y = (p_width//2)-(width//2), (p_height//2)-(height//2)pg.draw.rect(self.image, (0, 0, 0, 0), (center_x, center_y, width, height))pg.init()窗口 = pg.display.set_mode((300, 300))时钟 = pg.time.Clock()精灵 = 矩形()sprite.set_colour((255, 0, 0, 255))sprite.set_outline(50)group = pg.sprite.Group(精灵)颜色值 = 0颜色添加 = 5运行 = 真运行时:时钟滴答(60)对于 pg.event.get() 中的事件:如果 event.type == pg.QUIT:运行 = 错误sprite.set_colour((min(colorVal, 255), max(0, min(511-colorVal, 255)), 0, 255))colorVal += colorAdd如果 colorVal <= 0 或 colorVal >= 511:颜色添加 *= -1window.fill(0)group.draw(窗口)pg.display.flip()

I want to change the colour of a rect dynamically during runtime. Currently set_colour is filling all of the pixels of the surface with a single colour value. This works, but an issue arises when a method like set_outline is called, which modifies the transparency of the surface.

class Rectangle(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self.original_image = pg.Surface((10, 10))
        self.image = self.original_image
        self.rect = self.image.get_rect()

    def set_colour(self, colour_value):
        self.colour = colour_value
        self.image.fill(self.colour)
        self.original_image.fill(self.colour)

    def set_outline(self, thickness):
        self.thickness = thickness
        size = self.image.get_size()

        calc = thickness/100
        p_width, p_height = size[0], size[1]
        width, height = size[0]*calc, size[1]*calc

        self.image = self.image.convert_alpha()

        center_x, center_y = (p_width//2)-(width//2), (p_height//2)-(height//2)
        pg.draw.rect(self.image, (0, 0, 0, 0), (center_x, center_y, width, height))

Now if I try to change the colour of that rect during runtime, it will overwrite all of those transparent pixels created in set_outline.

Is there a way to mask or blend the colour on to the rect, so it's not replacing any of the transparency?

解决方案

You can achieve this by 2 steps. self.original_image contains the filled rectangle with the desired color:

self.original_image.fill(self.colour)

Generate a completely white rectangle and transparent areas. Blend the rectangle with (self.image) and the blend mode BLEND_MAX (see pygame.Surface.blit):

whiteTransparent = pg.Surface(self.image.get_size(), pg.SRCALPHA)
whiteTransparent.fill((255, 255, 255, 0))
self.image.blit(whiteTransparent, (0, 0), special_flags=pg.BLEND_MAX)

Now the rectangle is completely white, but the transparent areas are kept. Use the blend mode BLEND_MULT and blend self.original_image with self.image to get the desired result:

self.image.blit(self.original_image, (0, 0), special_flags=pg.BLEND_MULT)


Minimal example:

import pygame as pg

class Rectangle(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self.original_image = pg.Surface((150, 150))
        self.image = self.original_image
        self.rect = self.image.get_rect(center = (150, 150))

    def set_colour(self, colour_value):
        self.colour = colour_value
        self.original_image.fill(self.colour)

        whiteTransparent = pg.Surface(self.image.get_size(), pg.SRCALPHA)
        whiteTransparent.fill((255, 255, 255, 0))
        self.image.blit(whiteTransparent, (0, 0), special_flags=pg.BLEND_MAX)

        self.image.blit(self.original_image, (0, 0), special_flags=pg.BLEND_MULT)

    def set_outline(self, thickness):
        self.thickness = thickness
        size = self.image.get_size()

        calc = thickness/100
        p_width, p_height = size[0], size[1]
        width, height = size[0]*calc, size[1]*calc

        self.image = self.image.convert_alpha()

        center_x, center_y = (p_width//2)-(width//2), (p_height//2)-(height//2)
        pg.draw.rect(self.image, (0, 0, 0, 0), (center_x, center_y, width, height))

pg.init()
window = pg.display.set_mode((300, 300))
clock = pg.time.Clock()

sprite = Rectangle()
sprite.set_colour((255, 0, 0, 255))
sprite.set_outline(50)

group = pg.sprite.Group(sprite)

colorVal = 0
colorAdd = 5
run = True
while run:
    clock.tick(60)
    for event in pg.event.get():
        if event.type == pg.QUIT:
            run = False

    sprite.set_colour((min(colorVal, 255), max(0, min(511-colorVal, 255)), 0, 255))
    colorVal += colorAdd
    if colorVal <= 0 or colorVal >= 511:
        colorAdd *= -1

    window.fill(0)
    group.draw(window)
    pg.display.flip()

这篇关于在不覆盖透明度的情况下更改表面的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆