如何聚焦光线或如何仅在 pygame 中绘制窗口的某些圆形部分?

Posted

技术标签:

【中文标题】如何聚焦光线或如何仅在 pygame 中绘制窗口的某些圆形部分?【英文标题】:How do I focus light or how do I only draw certain circular parts of the window in pygame? 【发布时间】:2020-05-07 12:11:04 【问题描述】:

为此,如果您熟悉它,请考虑一下 Super Mario Maker 2 中嘘级别中的黑暗模式。我正在尝试在角色周围创建一个圆形聚光灯,这也会使圆圈范围内的任何东西都可见(例如,站立的部分地板、敌人或现场的其他任何东西)。我的计划是先画圆圈/聚光灯,然后是场景,然后是角色。然后我希望任何没有被聚光灯突出显示的东西都被涂黑。

所以我的问题是:

有人知道如何填满整个屏幕,但圆圈内的内容除外?

【问题讨论】:

【参考方案1】:

我建议一个解决方案,它结合了一个剪切区域pygame.Surface.set_clip,并在中心绘制一个带有圆形透明区域的黑色矩形。

定义一个半径并创建一个半径为两倍的正方形pygame.Surface

radius = 50
cover_surf = pygame.Surface((radius*2, radius*2))

设置一个标识透明颜色的白色键(set_colorkey)并在表面上绘制一个白色(透明)圆圈:

cover_surf.set_colorkey((255, 255, 255))
pygame.draw.circle(cover_surf, (255, 255, 255), (radius, radius), radius)

定义你想看到的圆形区域的中心(在下面的clip_center)。 在主应用程序循环中,清除显示并设置剪切区域,绘制场景。在您更新剪辑区域中的显示绘制cover_surf之前:

while run:
    # [...]

    # clear screen and set clipping region
    screen.fill(0)    
    clip_rect = pygame.Rect(clip_center[0]-radius, clip_center[1]-radius, radius*2, radius*2)
    screen.set_clip(clip_rect)

    # draw the scene
    # [...]

    # draw transparent circle and update display
    screen.blit(cover_surf, clip_rect)
    pygame.display.flip()

最小示例: repl.it/@Rabbid76/PyGame-ClipCircularRegion-2

import pygame
pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

radius = 50
cover_surf = pygame.Surface((radius*2, radius*2))
cover_surf.fill(0)
cover_surf.set_colorkey((255, 255, 255))
pygame.draw.circle(cover_surf, (255, 255, 255), (radius, radius), radius)

run = True
while run:
    clock.tick(60)

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

    clip_center = pygame.mouse.get_pos()

    # clear screen and set clipping region
    screen.fill(0)    
    clip_rect = pygame.Rect(clip_center[0]-radius, clip_center[1]-radius, radius*2, radius*2)
    screen.set_clip(clip_rect)

    # draw the scene
    for x in range(10):
        for y in range(10):
            color = (255, 255, 255) if (x+y) % 2 == 0 else (255, 0, 0)
            pygame.draw.rect(screen, color, (x*50, y*50, 50, 50))

    # draw transparent circle and update display
    screen.blit(cover_surf, clip_rect)
    pygame.display.flip()

如果你想要多个圆形绘图区域,那么创建一个与显示相同大小的pygame.Surface.set_clip并设置白色颜色键:

cover_surf = pygame.Surface((400, 400))
cover_surf.set_colorkey((255, 255, 255))

将整个曲面填充为黑色,并在曲面上绘制白色圆圈:

cover_surf.fill(0)
pygame.draw.circle(cover_surf, (255, 255, 255), (100, 100), 50)
pygame.draw.circle(cover_surf, (255, 255, 255), (300, 300), 70)

在更新显示之前,在窗口上粘贴cover_surf

while run:
    # [...]

    # draw transparent circle and update display
    screen.blit(cover_surf, (0, 0))
    pygame.display.flip()

最小示例: repl.it/@Rabbid76/PyGame-ClipCircularRegion-3

import pygame
pygame.init()
screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

cover_surf = pygame.Surface((400, 400))
cover_surf.set_colorkey((255, 255, 255))

px = [100, 200, 300]
dx = [1, 2, 3] 

run = True
while run:
    clock.tick(60)

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

    # create cover surface
    cover_surf.fill(0)
    for i in range(3):
        radius = 40 + i*20
        pygame.draw.circle(cover_surf, (255, 255, 255), (px[i], 100+(i*100)), radius)
        px[i] += dx[i]
        if px[i] < radius or px[i] > 400 - radius:
            dx[i] = -dx[i]
        
    # draw the scene
    for x in range(10):
        for y in range(10):
            color = (255, 255, 255) if (x+y) % 2 == 0 else (255, 0, 0)
            pygame.draw.rect(screen, color, (x*50, y*50, 50, 50))

    # draw transparent circle and update display
    screen.blit(cover_surf, (0, 0))
    pygame.display.flip()

【讨论】:

以上是关于如何聚焦光线或如何仅在 pygame 中绘制窗口的某些圆形部分?的主要内容,如果未能解决你的问题,请参考以下文章

在Pygame中绘制一个又一个的图像

如何在pygame中围绕精灵或图像绘制边框?

模糊边缘的着色器,或如何绘制光线

如何检查 Chrome 窗口是不是聚焦?

使用pygame绘制图像的好方法是啥?

PyGame快速入门