在pygame中使用多行渲染文本

时间:2017-02-02 23:23:26

标签: python pygame render

我正在尝试制作游戏而我正在尝试渲染大量文本。当文本呈现时,文本的其余部分离开屏幕。有没有简单的方法让文本转到pygame窗口的下一行?

helpT = sys_font.render \
                ("This game is a combination of all of the trends\n of 2016. When you press 'Start Game,' a menu will pop up. In order to beat the game, you must get a perfect score on every single one of these games.",0,(hecolor))
        screen.blit(helpT,(0, 0))

10 个答案:

答案 0 :(得分:7)

正如我在评论中所说;你必须分别渲染每个单词并计算文本的宽度是否扩展了表面(或屏幕)的宽度。这是一个例子:

import pygame
pygame.init()


SIZE = WIDTH, HEIGHT = (1024, 720)
FPS = 30
screen = pygame.display.set_mode(SIZE, pygame.RESIZABLE)
clock = pygame.time.Clock()


def blit_text(surface, text, pos, font, color=pygame.Color('black')):
    words = [word.split(' ') for word in text.splitlines()]  # 2D array where each row is a list of words.
    space = font.size(' ')[0]  # The width of a space.
    max_width, max_height = surface.get_size()
    x, y = pos
    for line in words:
        for word in line:
            word_surface = font.render(word, 0, color)
            word_width, word_height = word_surface.get_size()
            if x + word_width >= max_width:
                x = pos[0]  # Reset the x.
                y += word_height  # Start on new row.
            surface.blit(word_surface, (x, y))
            x += word_width + space
        x = pos[0]  # Reset the x.
        y += word_height  # Start on new row.


text = "This is a really long sentence with a couple of breaks.\nSometimes it will break even if there isn't a break " \
       "in the sentence, but that's because the text is too long to fit the screen.\nIt can look strange sometimes.\n" \
       "This function doesn't check if the text is too high to fit on the height of the surface though, so sometimes " \
       "text will disappear underneath the surface"
font = pygame.font.SysFont('Arial', 64)

while True:

    dt = clock.tick(FPS) / 1000

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

    screen.fill(pygame.Color('white'))
    blit_text(screen, text, (20, 20), font)
    pygame.display.update()

结果

enter image description here

答案 1 :(得分:2)

没有简单的方法在pygame中的多行上呈现文本,但是这个帮助函数可以为你提供一些用途。只需传入您的文字(带换行符),x,y和字体大小。

def render_multi_line(text, x, y, fsize)
        lines = text.splitlines()
        for i, l in enumerate(lines):
            screen.blit(sys_font.render(l, 0, hecolor), (x, y + fsize*i))

答案 2 :(得分:2)

这将类似于其他人发布的内容,但我想我也会上传自己的代码:

    def box_text(surface, font, x_start, x_end, y_start, text, colour):
        x = x_start
        y = y_start
        words = text.split(' ')

        for word in words:
            word_t = font.render(word, True, colour)
            if word_t.get_width() + x <= x_end:
                surface.blit(word_t, (x, y))
                x += word_t.get_width() + 2
            else:
                y += word_t.get_height() + 4
                x = x_start
                surface.blit(word_t, (x, y))
                x += word_t.get_width() + 2

我认为这是不言自明的,您输入您希望文本开始的位置 (x_start) 以及它应该结束的位置,然后它几乎会一直下降,直到您输入的字符串完成。

我在个人项目中使用的示例:

x_start = self.W / 2 - info_box.get_width() / 2 + 10

self.box_text(self.WINDOW, self.info_font, x_start, x_start + 430, self.H / 3 + 10, self.mage_text, self.white)

如果您希望文本合理,则必须进行一些小的更改。

答案 3 :(得分:1)

创建了一个可能会有所帮助的函数:)只要确保每个新段落都是您要在此函数上调用的列表中的一个新项即可。

def multilineText(Surface, textAsList: list, font: str, size: int, colour, antialias: bool, centerTupleCoord: tuple, spaceBetweenLines: int):
    xPosition = centerTupleCoord[0]
    yPosition = centerTupleCoord[1]
    for paragraph in textAsList:
        fontObjsrt = pygame.font.SysFont(font, size)
        TextSurf = fontObjsrt.render(paragraph, antialias, colour)
        TextRect = TextSurf.get_rect()
        TextRect.center = (xPosition, yPosition)
        Surface.blit(TextSurf, TextRect)
        yPosition += spaceBetweenLines

答案 4 :(得分:0)

我就这样做了

amfolyt_beskrivelse_text = ['en amfolyt er et stof som både kan være en base, eller syre','så som']
    for x in amfolyt_beskrivelse_text:
        descriptioncounter += 1
        screen.blit((pygame.font.SysFont('constantia',12).render(x, True, BLACK)),(300,10*descriptioncounter))
    descriptioncounter = 0

但当然,我只能这样做,因为我的文字从屏幕顶部开始一行距离。如果你从屏幕下方开始,你就可以做到

(300,12+12*descriptioncounter)

答案 5 :(得分:0)

您可以做的一件事是使用等宽字体。它们对于所有角色都具有相同的大小,因此受到程序员的喜爱。这将是我处理高度/宽度问题的解决方案。

答案 6 :(得分:0)

您可以使用.json文件加载每一行。

.json文件(称为first.json):

["Hello!", "How's it going?"]

然后将其加载到文件中

sys_font = pygame.font.SysFont(("Arial"),30)

def message_box(text):
    pos = 560 # depends on message box location
    pygame.draw.rect(root, (0,0,0), (100, 550, 800, 200)) #rectangle position varies
    for x in range(len(text)):
        rendered = sys_font.render(text[x], 0, (255,255,255))
        root.blit(rendered, ( 110, pos))
        pos += 30 # moves the following line down 30 pixels

with open('first.json') as text:
    message_box(json.load(text))

别忘了import json

结果:enter image description here

希望这会有所帮助!

答案 7 :(得分:0)

我建议使用ptext库,该库能够识别换行符(\n)。您只需要致电ptext.draw(text, position)

import pygame as pg
import ptext


pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
BLUE = pg.Color('dodgerblue')
# Triple quoted strings contain newline characters.
text = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum."""

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True

    screen.fill(BG_COLOR)
    ptext.draw(text, (10, 10), color=BLUE)  # Recognizes newline characters.
    pg.display.flip()
    clock.tick(60)

pg.quit()

pygame multiline text

答案 8 :(得分:0)

在先前的答案的基础上,我做了一个比较全面的blit文本功能,可以通过一个简短的命令使用它:

def blittext(text, **kwargs):
    #blit text into screen, uses defaults and works for multiline strings
    fontface = kwargs.get('font', 'PressStart2P-Regular.ttf')
    b = kwargs.get('bold', False)
    fontsize = kwargs.get('size', 30)
    color = kwargs.get('color', (255, 255, 255))
    topleft = kwargs.get('topleft',(w/2,h/2))
    center = kwargs.get('center')
    textsurf = kwargs.get('surface',surface)
    maxwidth = kwargs.get('width',w)
    try:
        myfont = pygame.font.Font('/storage/emulated/0/games/' + fontface, fontsize)
    except:
        myfont = pygame.font.SysFont(fontface, fontsize, bold=b)
    x,y = topleft
    charwidth = myfont.size(' ')[0]
    charheight = fontsize + 3
    
    if center:
        for l in text.splitlines():
            mytext = myfont.render(l, False, color)
            textrect = mytext.get_rect(center=center)
            center = (center[0],center[1]+charheight)
            textsurf.blit(mytext,textrect)      
    else:
        for line in text.splitlines():
            for word in line.split(' '):
                mytext = myfont.render(word, False, color)
                textrect = mytext.get_rect(topleft=(x,y))
                wordwidth = textrect.width
                if x + wordwidth >= maxwidth:
                    x,y = (topleft[0], y + charheight)
                textsurf.blit(mytext,(x,y))
                x += charwidth + wordwidth
            x,y = (topleft[0], y + charheight)

答案 9 :(得分:0)

没有自动解决方案。您必须自己实现文本环绕,并逐行逐字地绘制文本。
幸运的是,PyGame Wiki提供了用于此任务的功能。请参阅PyGame Wiki Simple Text Wrapping for pygame

我扩展了该函数并添加了一个附加参数,该参数提供了 left right 对齐的文本,居中的文本甚至是阻止模式:

textAlignLeft = 0
textAlignRight = 1
textAlignCenter = 2
textAlignBlock = 3

def drawText(surface, text, color, rect, font, align=textAlignLeft, aa=False, bkg=None):
    lineSpacing = -2
    spaceWidth, fontHeight = font.size(" ")[0], font.size("Tg")[1]

    listOfWords = text.split(" ")
    if bkg:
        imageList = [font.render(word, 1, color, bkg) for word in listOfWords]
        for image in imageList: image.set_colorkey(bkg)
    else:
        imageList = [font.render(word, aa, color) for word in listOfWords]

    maxLen = rect[2]
    lineLenList = [0]
    lineList = [[]]
    for image in imageList:
        width = image.get_width()
        lineLen = lineLenList[-1] + len(lineList[-1]) * spaceWidth + width
        if len(lineList[-1]) == 0 or lineLen <= maxLen:
            lineLenList[-1] += width
            lineList[-1].append(image)
        else:
            lineLenList.append(width)
            lineList.append([image])

    lineBottom = rect[1]
    lastLine = 0
    for lineLen, lineImages in zip(lineLenList, lineList):
        lineLeft = rect[0]
        if align == textAlignRight:
            lineLeft += + rect[2] - lineLen - spaceWidth * (len(lineImages)-1)
        elif align == textAlignCenter:
            lineLeft += (rect[2] - lineLen - spaceWidth * (len(lineImages)-1)) // 2
        elif align == textAlignBlock and len(lineImages) > 1:
            spaceWidth = (rect[2] - lineLen) // (len(lineImages)-1)
        if lineBottom + fontHeight > rect[1] + rect[3]:
            break
        lastLine += 1
        for i, image in enumerate(lineImages):
            x, y = lineLeft + i*spaceWidth, lineBottom
            surface.blit(image, (round(x), y))
            lineLeft += image.get_width() 
        lineBottom += fontHeight + lineSpacing

    if lastLine < len(lineList):
        drawWords = sum([len(lineList[i]) for i in range(lastLine)])
        remainingText = ""
        for text in listOfWords[drawWords:]: remainingText += text + " "
        return remainingText
    return ""

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

import pygame

pygame.init()
font = pygame.font.SysFont(None, 40)

msg = "Simple function that will draw text and wrap it to fit the rect passed.  If there is any text that will not fit into the box, the remaining text will be returned."
textRect = pygame.Rect(100, 100, 300, 300)

window = pygame.display.set_mode((500, 500))
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill((255, 255, 255))
    pygame.draw.rect(window, (0, 0, 0), textRect, 1)
    drawTextRect = textRect.inflate(-5, -5)
    drawText(window, msg, (0, 0, 0), drawTextRect, font, textAlignBlock, True)
    pygame.display.flip()