【问题标题】:Have an outline of text in Pygame在 Pygame 中有一个文本大纲
【发布时间】:2020-04-02 08:56:08
【问题描述】:

所以我有这个功能,它可以在屏幕上显示文本:

def text_speech(font : str ,size : int,text : str,color,x,y, bold : bool):
    SCREEN = width, height = 900, 600
    font = pygame.font.Font(font,size)
    font.set_bold(bold)
    text = font.render(text, True, color)
    textRect = text.get_rect()
    textRect.center = (x,y)
    screen.blit(text,textRect)

如果我这样做:

screen.fill((0,0,0))
text_speed('arialnarrow.ttf', 40, 'Hello', (255,255,255), (width/2), (height/2), False)

它会在带有白色文本的黑屏上生成世界“Hello”。如果用户将鼠标悬停在上面,是否有可能会创建一个红色 (255,0,0) 轮廓?

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    要完成一个大纲,您必须多次执行 blit。以轮廓颜色(红色)渲染文本:

    outlineSurf = font.render(text, True, (255, 0, 0))
    outlineSize = outlineSurf.get_size()
    

    创建一个比文本表面更大的表面。宽度和高度必须增加两倍的轮廓厚度:

    textSurf = pygame.Surface((outlineSize[0] + outline*2, outlineSize[1] + 2*outline))
    textRect = textSurf.get_rect()
    

    在文本表面上对轮廓表面进行 8 次 Blit,移动轮廓厚度(水平、垂直和对角线:

    offsets = [(ox, oy) 
        for ox in range(-outline, 2*outline, outline)
        for oy in range(-outline, 2*outline, outline)
        if ox != 0 or ox != 0]
    for ox, oy in offsets:   
        px, py = textRect.center
        textSurf.blit(outlineSurf, outlineSurf.get_rect(center = (px+ox, py+oy))) 
    

    使用文本颜色渲染文本并将表面转换为每像素 alpha 格式 (convert_alpha):

    innerText = font.render(text, True, color).convert_alpha()
    

    textSurf中间的文字进行blit:

    textSurf.blit(innerText, innerText.get_rect(center = textRect.center)) 
    

    textSurf 粘贴到窗口上:

    textRect.center = (x,y)
    screen.blit(textSurf, textRect)
    

    看例子:

    import pygame
    import pygame.font
    
    pygame.init()
    
    width, height = 400, 300
    screen = pygame.display.set_mode((width, height))
    clock = pygame.time.Clock()
    textRect = pygame.Rect(0, 0, 0, 0)
    
    def text_speech(font : str, size : int, text : str, color, x, y, bold : bool, outline: int):
        global textRect 
        # font = pygame.font.Font(font,size)
        font = pygame.font.SysFont(None, size)
        font.set_bold(True)
        if outline > 0:
            outlineSurf = font.render(text, True, (255, 0, 0))
            outlineSize = outlineSurf.get_size()
            textSurf = pygame.Surface((outlineSize[0] + outline*2, outlineSize[1] + 2*outline))
            textRect = textSurf.get_rect()
            offsets = [(ox, oy) 
                for ox in range(-outline, 2*outline, outline)
                for oy in range(-outline, 2*outline, outline)
                if ox != 0 or ox != 0]
            for ox, oy in offsets:   
                px, py = textRect.center
                textSurf.blit(outlineSurf, outlineSurf.get_rect(center = (px+ox, py+oy))) 
            innerText = font.render(text, True, color).convert_alpha()
            textSurf.blit(innerText, innerText.get_rect(center = textRect.center)) 
        else:
            textSurf = font.render(text, True, color)
            textRect = textSurf.get_rect()    
    
        textRect.center = (x,y)
        screen.blit(textSurf, textRect)
    
    run = True
    while run:
        clock.tick(60)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        hover = textRect.collidepoint(pygame.mouse.get_pos())
        outlineSize = 3 if hover else 0 
    
        screen.fill((0,0,0))
        text_speech('arialnarrow.ttf', 40, 'Hello', (255,255,255), (width/2), (height/2), False, outlineSize)
        pygame.display.flip()
    

    【讨论】:

    • 老实说,你们两个都是对的,但是你只是在整个文本周围画了一个轮廓。非常感谢!
    • @underscoreC 谢谢。如果你想使用 pygame.font 模块,那么这是唯一的选择。当然 pygame.freetype 模块会提供更大范围的机会。
    • @Rabbid76 嘿,很抱歉像这样插入我自己,但你介意解释一下你为什么在那里使用.convert_alpha() 吗?我或多或少了解该命令的作用,但我只是不明白为什么有人会使用它。如果它与性能有关,是否值得用它来对轮廓进行 blitting?因为每次迭代都对 24 个文本对象进行 blitting 让我的粉丝流血了。 (我有 3 个地方需要不断地画大纲)
    • @hellwraiz convert()convert_alpha()) 确保 a Surface 具有与显示 Surface 相同的像素格式。当图像在显示器上为blit 时,这会提高性能,因为格式是兼容的并且blit 不需要执行隐式转换。见Lag when win.blit() background pygame
    【解决方案2】:

    假设“轮廓”是指围绕它的笔划,我有一个简单的解决方案。只需渲染相同的文本,以与您已经编写的文本相同的位置为中心,稍大一点并用红色显示。然后,只需检查鼠标何时悬停在初始文本的矩形上,如果是,则对轮廓进行 blit。

    为此,我们需要提取您的第一个文本的矩形。我更改了您的功能,以便它输出渲染的表面和矩形。

    我还做了一些其他的调整:

    • 您不需要每次都生成font 并渲染文本,这会浪费CPU 周期。我建议为每种尺寸/字体将每种字体设置为全局常量
    • 您在函数中定义了screen,但从不使用它。我更改了函数,使其不再进行渲染。
    • 当您致电text_speech(我认为您的第二次使用是一个错字)时,widthheight 不涉及任何内容。我还将它们定义为全局常量,我将其设置为您的显示尺寸。

    您没有包含任何显示代码,所以我为运行概念编写了最低限度的代码。

    import pygame
    
    pygame.init()
    
    # Font constants
    ARIALNARROW_40 = font = pygame.font.Font('arialnarrow.ttf', 40)
    ARIALNARROW_42 = font = pygame.font.Font('arialnarrow.ttf', 42)
    
    # Screen size
    WIDTH = 900
    HEIGHT = 600
    
    def text_speech(font, text, color, x, y, bold):
        font.set_bold(bold)
        rendered_text = font.render(text, True, color)
    
        # Directly center the rect upon its creation
        text_rect = rendered_text.get_rect(center=(x,y))
        return text_rect, rendered_text
    
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    
    inner_rect, inner_text = text_speech(
        ARIALNARROW_40, 'Hello', (255, 255, 255),
        (WIDTH / 2), (HEIGHT / 2), False
    )
    
    # For your outline
    outline_rect, outline_text = text_speech(
        ARIALNARROW_42, 'Hello', (255, 0, 0),
        (WIDTH / 2), (HEIGHT / 2), False
    )
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()
    
    
        # Paint our screen
        screen.fill((0,0,0))
    
        if inner_rect.collidepoint(pygame.mouse.get_pos()):
            # Touching our text! Render outline
            screen.blit(outline_text, outline_rect)
    
        screen.blit(inner_text, inner_rect)
    
    
        # Enact our display changes
        pygame.display.update()
    

    注意这确实增加了“侧面缩放”的潜在不良影响。然而,解决这个问题意味着你要么必须弄乱字体字距调整(使用pygame.freetype 模块),但这可能会很快变得非常混乱,或者你可以提前预渲染笔画图像(并使用与我使用的逻辑相同),但这需要您在每次更改文本时重新渲染所有文本表面。

    【讨论】:

    • 你也说得对,但我更喜欢他的方法,因为它是一个完整的轮廓。我道歉
    • 但是,我确实喜欢您的文本表示一种 3d 阴影的方式,但我不希望这样。不过很酷。
    • 不用道歉,他的方法确实做得更好?。不客气。
    猜你喜欢
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多