如何更改 pygame 中一段文本的颜色

how to change the color a section of text in pygame

我正在使用 pygame 创建一个游戏,当您键入该字母时,该字母的颜色会发生变化。喜欢nitrotype.com。但是问题是我不知道如何改变单个字母的颜色。 我无法清除屏幕然后执行此操作,因为那样会改变整条线的颜色。 因此,要么我需要一种方法来更改单个字母的颜色,要么需要一种将单个字母一次一个地显示在屏幕上的方法。但是我不知道如何统一放置字母(这样结尾的句子居中)。请有人帮我解决这个问题。要么告诉我如何改变单个字母的颜色,要么告诉我如何完美地放置单个字母然后改变它们的颜色。

import pygame as pg
import pygame

pg.init()
screenHeight, screenWidth = 600, 800
gameDisplay = pg.display.set_mode((screenWidth, screenHeight))
pg.display.set_caption("Nitrotype")

black = (255, 255, 255)
white = (0, 0, 0)
gameDisplay.fill(white)
pg.display.update()

gameOn = True
with open("text.txt", "r") as f:
    contents = f.read()

def msgToScreen(msg, color, size):
    cur = []
    strings = []
    words = msg.split(" ")
    for i in words:
        cur.append(i)
        if len(" ".join(cur)) >= 35:
            strings.append(" ".join(cur))
            cur = []
    if cur != []:strings.append(" ".join(cur))
    
    curY = 20
    
    for string in strings:
        font = pg.font.SysFont(None, size)
        text = font.render(string, True, color)
        text_rect = text.get_rect(center=(screenWidth/2, curY))
        gameDisplay.blit(text, text_rect)
        curY += 40
    
    return text

textOnScreen = msgToScreen(contents, black, 50)

pg.display.update()

curIdx = 0
keyCombination = {"a":pg.K_a, "b":pg.K_b, "c":pg.K_c, "d":pg.K_d, "e":pg.K_e, "f":pg.K_f,
                "g":pg.K_g, "h":pg.K_h, "i":pg.K_i, "j":pg.K_j, "k":pg.K_k, "l":pg.K_l,
                "m":pg.K_m, "n":pg.K_n, "o":pg.K_o, "p":pg.K_p, "q":pg.K_q, "r":pg.K_r,
                "s":pg.K_s, "t":pg.K_t, "u":pg.K_u, "v":pg.K_v, "w":pg.K_w, "x":pg.K_x,
                "y":pg.K_y, "z":pg.K_z}
while gameOn:
    for event in pygame.event.get():
        if event.type == pg.QUIT:
            gameOn = False
        if event.type == pg.KEYDOWN:
            if event.key == keyCombination[contents[curIdx].lower()]:
                #Here is where the color of the current letter should change
                curIdx += 1

pg.quit()

在字体渲染过程中不能改变单个字母的颜色;您必须逐个字母地呈现文本。

您可以使用 render() 将每个字母渲染到它自己的表面并将它们 blit 到您的屏幕,但是您必须手动计算每个字母应该去哪里。

如果使用新的 freetype 模块会更容易一些,它在 Font class 中有很多方便的函数,比如 origin, get_rect and get_metrics 可以计算每个字母有多大。

这是我一起破解的一个简单示例。它并不完美,但你会明白的。

import pygame
import pygame.freetype
from itertools import cycle

def main():
    pygame.init()
    screen = pygame.display.set_mode((800, 600))

    # just some demo data for you to type
    data = cycle(['This is an example.', 'This is another, longer sentence.'])
    current = next(data)
    current_idx = 0 # points to the current letter, as you have already guessed
    
    font = pygame.freetype.Font(None, 50)
    # the font in the new freetype module have an origin property.
    # if you set this to True, the render functions take the dest position 
    # to be that of the text origin, as opposed to the top-left corner
    # of the bounding box
    font.origin = True
    font_height = font.get_sized_height()
    
    # we want to know how much space each letter takes during rendering.
    # the item at index 4 is the 'horizontal_advance_x'
    M_ADV_X = 4
    
    # let's calculate how big the entire line of text is
    text_surf_rect = font.get_rect(current)
    # in this rect, the y property is the baseline
    # we use since we use the origin mode
    baseline = text_surf_rect.y
    # now let's create a surface to render the text on
    # and center it on the screen
    text_surf = pygame.Surface(text_surf_rect.size)
    text_surf_rect.center = screen.get_rect().center
    # calculate the width (and other stuff) for each letter of the text
    metrics = font.get_metrics(current)

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.KEYDOWN:
                if e.unicode == current[current_idx].lower():
                    # if we press the correct letter, move the index
                    current_idx += 1
                    if current_idx >= len(current):
                        # if the sentence is complete, let's prepare the
                        # next surface
                        current_idx = 0
                        current = next(data)
                        text_surf_rect = font.get_rect(current)
                        baseline = text_surf_rect.y
                        text_surf = pygame.Surface(text_surf_rect.size)
                        text_surf_rect.center = screen.get_rect().center
                        metrics = font.get_metrics(current)

        # clear everything                        
        screen.fill('white')
        text_surf.fill('white')
        
        x = 0
        # render each letter of the current sentence one by one
        for (idx, (letter, metric)) in enumerate(zip(current, metrics)):
            # select the right color
            if idx == current_idx:
                color = 'lightblue'
            elif idx < current_idx:
                color = 'lightgrey'
            else:
                color = 'black'
            # render the single letter
            font.render_to(text_surf, (x, baseline), letter, color)
            # and move the start position
            x += metric[M_ADV_X]
          
        screen.blit(text_surf, text_surf_rect)
        pygame.display.flip()

if __name__ == '__main__':
    main()

使用第二个 Surface 并使用 Rect class' center 属性.

很容易使文本居中