在pygame中绘制透明矩形和多边形

64 投票
4 回答
114063 浏览
提问于 2025-04-16 19:30

我该如何画一个带有透明度的矩形呢?
我现在有:

windowSurface = pygame.display.set_mode((1000, 750), pygame.DOUBLEBUF)
pygame.draw.rect(windowSurface, pygame.Color(255, 255, 255, 128), pygame.Rect(0, 0, 1000, 750))

但是我想让这个白色矩形变成50%透明的样子,可是透明度的设置似乎没有效果。

4 个回答

2

我能帮你做的就是教你怎么画一个没有填充颜色的矩形。

画这个矩形的代码是:

pygame.draw.rect(surface, [255, 0, 0], [50, 50, 90, 180], 1)

这里的“1”表示这个矩形是空心的,也就是说里面没有颜色填充。

22

很遗憾,直接画透明形状的方法并不好。你可以看看 pygame.draw 模块的说明:

颜色的透明度值会直接写入表面上,但绘制函数不会透明绘制。

所以,你不能直接用 'pygame.draw' 模块来画透明形状。这个模块不会把形状和目标表面混合在一起。你需要先在一个支持透明度的表面上(使用 RGBA 格式)绘制形状。然后你可以用 blit 方法将这个表面混合到目标表面上。具体可以参考 在 pygame 中绘制透明矩形和多边形。因此,你需要采取一些变通的方法:

  1. 创建一个 pygame.Surface 对象,设置为每个像素都有透明度,并且大小要足够覆盖你要绘制的形状。
  2. 在这个 _Surface 上绘制形状。
  3. 将这个 Surface 和目标 Surface 混合。默认情况下,blit() 方法会混合两个 Surfaces

例如,这里有三个函数,可以绘制透明的矩形、圆形和多边形:

def draw_rect_alpha(surface, color, rect):
    shape_surf = pygame.Surface(pygame.Rect(rect).size, pygame.SRCALPHA)
    pygame.draw.rect(shape_surf, color, shape_surf.get_rect())
    surface.blit(shape_surf, rect)
def draw_circle_alpha(surface, color, center, radius):
    target_rect = pygame.Rect(center, (0, 0)).inflate((radius * 2, radius * 2))
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.circle(shape_surf, color, (radius, radius), radius)
    surface.blit(shape_surf, target_rect)
def draw_polygon_alpha(surface, color, points):
    lx, ly = zip(*points)
    min_x, min_y, max_x, max_y = min(lx), min(ly), max(lx), max(ly)
    target_rect = pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y)
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.polygon(shape_surf, color, [(x - min_x, y - min_y) for x, y in points])
    surface.blit(shape_surf, target_rect)

最简单的例子: repl.it/@Rabbid76/PyGame-TransparentShapes

import pygame

def draw_rect_alpha(surface, color, rect):
    shape_surf = pygame.Surface(pygame.Rect(rect).size, pygame.SRCALPHA)
    pygame.draw.rect(shape_surf, color, shape_surf.get_rect())
    surface.blit(shape_surf, rect)

def draw_circle_alpha(surface, color, center, radius):
    target_rect = pygame.Rect(center, (0, 0)).inflate((radius * 2, radius * 2))
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.circle(shape_surf, color, (radius, radius), radius)
    surface.blit(shape_surf, target_rect)

def draw_polygon_alpha(surface, color, points):
    lx, ly = zip(*points)
    min_x, min_y, max_x, max_y = min(lx), min(ly), max(lx), max(ly)
    target_rect = pygame.Rect(min_x, min_y, max_x - min_x, max_y - min_y)
    shape_surf = pygame.Surface(target_rect.size, pygame.SRCALPHA)
    pygame.draw.polygon(shape_surf, color, [(x - min_x, y - min_y) for x, y in points])
    surface.blit(shape_surf, target_rect)

pygame.init()
window = pygame.display.set_mode((250, 250))
clock = pygame.time.Clock()

background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (160, 160, 160), (192, 192, 192)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
    pygame.draw.rect(background, color, rect)

run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.blit(background, (0, 0))

    draw_rect_alpha(window, (0, 0, 255, 127), (55, 90, 140, 140))
    draw_circle_alpha(window, (255, 0, 0, 127), (150, 100), 80)
    draw_polygon_alpha(window, (255, 255, 0, 127), 
        [(100, 10), (100 + 0.8660 * 90, 145), (100 - 0.8660 * 90, 145)])

    pygame.display.flip()

pygame.quit()
exit()
93

pygame.draw 的绘图功能不支持透明度。文档中提到:

大多数参数都接受一个颜色参数,这个颜色是一个RGB三元组。它们也可以接受一个RGBA四元组。透明度值会直接写入表面(Surface),如果它包含像素透明度,但绘图函数不会以透明的方式绘制。

你可以创建一个第二个表面,然后把它绘制到屏幕上。这样做会进行透明度混合和颜色键处理。而且,你可以在表面级别设置透明度(这样更快,占用内存少),或者在像素级别设置透明度(这样更慢,但更精确)。你可以选择其中一种方式:

s = pygame.Surface((1000,750))  # the size of your rect
s.set_alpha(128)                # alpha level
s.fill((255,255,255))           # this fills the entire surface
windowSurface.blit(s, (0,0))    # (0,0) are the top-left coordinates

或者,

s = pygame.Surface((1000,750), pygame.SRCALPHA)   # per-pixel alpha
s.fill((255,255,255,128))                         # notice the alpha value in the color
windowSurface.blit(s, (0,0))

要记住的是,在第一种情况下,你在 s 上绘制的其他内容都会带上你指定的透明度值。所以如果你是用这个来绘制覆盖控件,比如说,使用第二种方式可能会更好。

另外,考虑使用 pygame.HWSURFACE 来创建硬件加速的表面。

可以查看 Surface 文档,特别是介绍部分。

撰写回答