“A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment.”
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
Related Stack Overflow questions:
Related Stack Overflow questions:
Minimal pygame.font
module example
Minimal pygame.freetype
module example
repl.it/@Rabbid76/PyGame-FreeTypeText
There are 2 possibilities. In either case PyGame has to be initialized by pygame.init
.
import pygame
pygame.init()
Use either the pygame.font
module and create a pygame.font.SysFont
or pygame.font.Font
object. render()
a pygame.Surface
with the text and blit
the Surface to the screen:
my_font = pygame.font.SysFont(None, 50)
text_surface = myfont.render("Hello world!", True, (255, 0, 0))
screen.blit(text_surface, (10, 10))
Or use the pygame.freetype
module. Create a pygame.freetype.SysFont()
or pygame.freetype.Font
object. render()
a pygame.Surface
with the text or directly render_to()
the text to the screen:
my_ft_font = pygame.freetype.SysFont('Times New Roman', 50)
my_ft_font.render_to(screen, (10, 10), "Hello world!", (255, 0, 0))
Related Stack Overflow questions:
Use pygame.font.SysFont
instead of pygame.font.Font
:
font = pygame.font.SysFont('comicsansms', size)
Or use pygame.font.match_font()
to find the path to a specific font file:
comicsansms_file = pygame.font.match_font('comicsansms')
font = pygame.font.Font(comicsansms_file, size)
Related Stack Overflow questions:
Make a Single Word Within a String Bold
📁 Minimal example - Bold text
📁 Minimal example - Bold text freetype
To draw a”bold” text the “bold” version of the font must be used. “bold” isn’t a flag or attribute, it’s just a different font.
Use pygame.font.match_font()
to find the path to a specific font file.
With the pygame.freetype
modle the text can be rendered with different styles like STYLE_DEFAULT
and STYLE_STRONG
. However, the text can only be rendered with one style at a time.
Related Stack Overflow questions:
how to make PNG canvas see-through in pygame when blitting image
I want to use Pygame’s freetype module to load a colorful emoji via its unicode. Unfortunately I only get a monochrome image with the outline of the emoji:
import pygame
import pygame.freetype
pygame.init()
window = pygame.display.set_mode((200, 200))
seguisy80 = pygame.freetype.SysFont("segoeuisymbol", 100)
emoji, rect = seguisy80.render('😃', "black")
rect.center = window.get_rect().center
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill("lightgray")
window.blit(emoji, rect)
pygame.display.flip()
pygame.quit()
How can I modify this code to get a full RGBA color image of an emoji?
Unfortunately, colored font loading is not natively supported in Pygame. However, there is a workaround. First you need a colored emoji font. For example, you can download one here: Apple Color Emoji for Linux.
Load this font using https://freetype.org/. Install freetype-py
:
pip3 install freetype-py
For Windows users, it should be mentioned that the installed package does not support the font and results in an “unimplemented feature” exception. Download the package from Unofficial Windows Binaries for Python Extension Packages and install it. e.g.:
pip3 install freetype_py-2.2.0-cp310-cp310-win_amd64.whl
Now you’re prepared and can load an emoji from the font.Emojis and their Unicode can be found here: Emoticons (Unicode block). Copy the emoji or use the unicode and load the glyph:
import freetype
face = freetype.Face("AppleColorEmoji.ttf")
face.set_char_size(int(face.available_sizes[-1].size))
face.load_char('😀', freetype.FT_LOAD_COLOR) # or face.load_char('\U0001F603', freetype.FT_LOAD_COLOR)
The loaded glyph now needs to be turned into a pygame.Surface
. To do this, use NumPy.
How this works in detail is explained in the answer to the question: How do I convert an OpenCV (cv2) image (BGR and BGRA) to a pygame.Surface object.
import numpy as np
ft_bitmap = face.glyph.bitmap
bitmap = np.array(ft_bitmap.buffer, dtype=np.uint8).reshape((ft_bitmap.rows, ft_bitmap.width, 4))
bitmap[:, :, [0, 2]] = bitmap[:, :, [2, 0]]
emoji = pygame.image.frombuffer(bitmap.flatten(), (ft_bitmap.width, ft_bitmap.rows), 'RGBA')
import pygame
import freetype
import numpy as np
class Emojis:
def __init__(self):
self. face = freetype.Face("AppleColorEmoji.ttf")
self.face.set_char_size(int(self.face.available_sizes[-1].size))
def create_surface(self, unicode):
self.face.load_char(unicode, freetype.FT_LOAD_COLOR)
ft_bitmap = self.face.glyph.bitmap
bitmap = np.array(ft_bitmap.buffer, dtype=np.uint8).reshape((ft_bitmap.rows, ft_bitmap.width, 4))
bitmap[:, :, [0, 2]] = bitmap[:, :, [2, 0]]
return pygame.image.frombuffer(bitmap.flatten(), (ft_bitmap.width, ft_bitmap.rows), 'RGBA')
pygame.init()
window = pygame.display.set_mode((200, 200))
emojis = Emojis()
emoji = emojis.create_surface('😃')
#emoji = emojis.create_surface('\U0001F603')
rect = emoji.get_rect(center = window.get_rect().center)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill("lightgray")
window.blit(emoji, rect)
pygame.display.flip()
pygame.quit()
Related Stack Overflow questions:
pygame.Surface.get_rect.get_rect()
returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument. For example, the center of the rectangle can be specified with the keyword argument center
. These keyword argument are applied to the attributes of the pygame.Rect
before it is returned (see pygame.Rect
for a full list of the keyword arguments).
Get the text rectangle and place the center of the text rectangle on the center of the window rectangle:
text_rect = text.get_rect(center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
You can even get the center of the window from the display Surface :
text_rect = text.get_rect(center = screen.get_rect().center)
Or with the use of pygame.display.get_surface()
:
text_rect = text.get_rect(center = pygame.display.get_surface().get_rect().center)
A Surface can be drawn on another Surface using the blit
method. The second argument is either a tuple (x, y) representing the upper left corner or a rectangle. With a rectangle, only the upper left corner of the rectangle is taken into account. Therefore you can pass the text rectangle directly to blit
:
screen.blit(text, text_rect)
📁 minimal example - Render centered text
Related Stack Overflow questions:v
Related Stack Overflow questions:
Related Stack Overflow questions:
How to create a text input box with pygame?
How to make a string’s content appears on screen as we type on keyboard?
How to allow the user to type only under certain conditions in pygame?
Rendering text with multiple lines in pygame
Python/Pygame make text in Pygame wrap when in leaves the window
Use the KEYDOWN
event to get the input from the keyboard (see pygame.event
). The key that was pressed can be obtained from the key
attribute of the pygame.event.Event
object. unicode
contains a single character string that is the fully translated character. Add the character to the text when a key is pressed.
Two special keys need to be dealt with. If RETURN is pressed, the input is finished. If BACKSPACE is pressed, the last character of the input text must be removed:
if event.type == pygame.KEYDOWN and input_active:
if event.key == pygame.K_RETURN:
input_active = False
elif event.key == pygame.K_BACKSPACE:
text = text[:-1]
else:
text += event.unicode
📁 minimal example - Text input
Use the algorithm in a pygame.sprite.Sprite
class. Handle the event in the update
method.Determine whether the mouse clicks in the text entry field with collidepoint
(see How to detect when a rectangular object, image or sprite is clicked) and activate the text input box:
class TextInputBox(pygame.sprite.Sprite):
# [...]
def update(self, event_list):
for event in event_list:
if event.type == pygame.MOUSEBUTTONDOWN and not self.active:
self.active = self.rect.collidepoint(event.pos)
if event.type == pygame.KEYDOWN and self.active:
if event.key == pygame.K_RETURN:
self.active = False
elif event.key == pygame.K_BACKSPACE:
self.text = self.text[:-1]
else:
self.text += event.unicode
self.render_text()
Pass the list of events to the update
method of the Group that contains the Sprite:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
group.update(event_list)
📁 minimal example - Text input box
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:
📁 Minimal example - Word wrap
📁 Minimal example - Word wrap
repl.it/@Rabbid76/PyGame-TextWrap
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 ""
Related Stack Overflow questions:
Creating a font object is very time consuming because the font file has to be read and interpreted.
Related Stack Overflow questions:
When using the pygame.font
module, the alpha channel of the text color is not taken into account when rendering a text, but see pygame.font.Font.render
:
Antialiased images are rendered to 24-bit RGB images. If the background is transparent a pixel alpha will be included.
Changed in pygame 2.0: per-surface alpha can be combined with per-pixel alpha.
Hence it is completely sufficient to set the transparency after rendering the text with set_alpha
. This even works for anti-aliased text:
font = pygame.font.SysFont(None, 150)
text_surf = font.render('test text', True, (255, 0, 0))
text_surf.set_alpha(127)
window.blit(text_surf, (x, y))
📁 minimal example - Render transparent text with font module
repl.it/@Rabbid76/PyGame-TransparentText
By using the pygame.freetype
module, you can use a transparent color directly when creating a text surface:
ft_font = pygame.freetype.SysFont('Times New Roman', 150)
text_surf2, text_rect2 = ft_font.render('test text', (255, 0, 0, 128))
window.blit(text_surf2, (x, y))
Or if you are rendering the text directly onto a surface:
ft_font = pygame.freetype.SysFont('Times New Roman', 150)
ft_font.render_to(window, (x, y), 'test text', (255, 0, 0, 128))
📁 minimal example - Render transparent text with freetype module
repl.it/@Rabbid76/PyGame-TransparentFreeTypeText
📁 minimal example - Render transparent text with transparent background
repl.it/@Rabbid76/PyGame-TextTransparentBackground
Related Stack Overflow questions:
Related Stack Overflow questions:
Related Stack Overflow questions:
How to display image and text at the same time in python (like SanctuaryRPG)?
Related Stack Overflow questions:
Pygame Rendering Text 1 by 1 Causes Lag In Game How Do I Fix This?
Related Stack Overflow questions: