Rendering text with multiple lines in pygame

后端 未结 9 1596
日久生厌
日久生厌 2020-11-29 12:15

I am trying to make a game and I am trying to render a lot of text. When the text renders, the rest of the text goes off the screen. Is there any easy way to make the text g

9条回答
  •  野性不改
    2020-11-29 12:33

    There is no automatic solution. You have to implement the text wrap by yourself and draw the text line by line respectively word by word.
    Fortunately PyGame wiki provides a function that for this task. See PyGame wiki Simple Text Wrapping for pygame.

    I've extended the function and added an additional argument, which provides left or right aligned text, centerd text or even block mode:

    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 ""
    

    Minimal example: 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()
    

提交回复
热议问题