rendering freetype font with pygame - python

I was trying to print out just a simple title page using pygame.
My original code looked like:
import pygame
import pygame.freetype
pygame.init()
pygame.display.set_caption('hello world')
screen = pygame.display.set_mode((800, 600), 0, 32)
title_font = pygame.font.Font(".../Montserrat-BlackItalic.ttf", 24)
title = title_font.render('sup', False, (250, 250, 250))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.quit:
running = False
screen.fill((25, 25, 25))
screen.blit(title, (0, 0))
pygame.display.update()
pygame.quit()
And it works. However, the font was super blurry. I read that using freetype font will help to make it less blurry but when I tried, I received this error:
File ".../untitled1.py", line 22, in <module>
screen.blit(title, (0, 0))
TypeError: argument 1 must be pygame.Surface, not tuple
I only changed my code to look for the font type so that it looked like that:
title_font = pygame.freetype.Font(".../Montserrat-BlackItalic.ttf", 24)
How do I get less blurry fonts now?

The API interface of pygame.freetype is different from that of pygame,fon. The pygame.freetype module has 2 options to display the text. It can either create a Surface like the pygame.fornt module or it can render the text directly on the screen (respectively a Surface). pygame.freetype.Font.render returns a tuple with the rendered text and a rectangle size of the surface. The equivalent of
title_font = pygame.font.Font(".../Montserrat-BlackItalic.ttf", 24)
title = title_font.render('sup', False, (250, 250, 250))
screen.blit(title, (0, 0))
is either
ft_font = pygame.freetype.Font(".../Montserrat-BlackItalic.ttf", 24)
title_surf, title_rect = ft_font.render('sup', (250, 250, 250))
screen.blit(title_surf, title_rect)
or
ft_font = pygame.freetype.Font(".../Montserrat-BlackItalic.ttf", 24)
ft_font.render_to(screen, (0, 0), 'sup', (250, 250, 250))

Related

Pygame Text: Instead of colour, let the text show an image, or animation

Something that looks like this but I want the image and text editable.
Instead of having something like:
title = menuFont.render("COMPUTER INFORMATION!", 1, BLACK)
screen.blit(title, Rect(50, 100, 400, 400))
Is it possible for the colour in the text to be an image instead, or an animation?
EDIT:
For those curious... when I imported the imaged, I had to change the end of the code a bit
screen.blit(texture, (50, 50))
screen.fill(BG_COLOR)
screen.blit(text_surface, (50, 170))
pg.display.update()
clock.tick(30)
The screen.fill comes after the texture... just a heads up :)
To texture your text, you can first render the text in white, then blit the texture onto it and pass pygame.BLEND_RGB_MULT as the special_flags argument to use the multiply blend mode. The texture will appear only on the opaque parts of the text surface.
Also, make sure that your texture is bigger than the text surface, otherwise some parts of the text will remain unaffected.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray32')
FONT = pg.font.Font(None, 50)
# I create a grid texture for demonstration purposes here.
# Just load your image with pygame.image.load instead.
texture = pg.Surface((200, 100))
texture.fill((200, 100, 0))
for x in range(0, 201, 5):
pg.draw.line(texture, (0, 0, 0), (x, 0), (x, 200))
for y in range(0, 101, 5):
pg.draw.line(texture, (0, 0, 0), (0, y), (200, y))
# Render the text and use pure white as the color.
text_surface = FONT.render('Hello world!', True, (255, 255, 255))
# Now blit the texture onto the text surface and pass BLEND_RGB_MULT as
# the special_flags argument, so that only the opaque parts are affected.
text_surface.blit(texture, (0, 0), special_flags=pg.BLEND_RGB_MULT)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
screen.fill(BG_COLOR)
screen.blit(texture, (50, 50))
screen.blit(text_surface, (50, 170))
pg.display.flip()
clock.tick(30)
pg.quit()
Here's the animated version. You have to load the separate frames of the animation and do the same as above for each frame. Put the resulting surfaces into a list and then play them back in the main loop.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray32')
FONT = pg.font.Font(None, 50)
# I create a grid texture for demonstration purposes here.
# Just load your image with pygame.image.load instead.
texture = pg.Surface((200, 100))
texture.fill((200, 100, 0))
for x in range(0, 201, 5):
pg.draw.line(texture, (0, 0, 0), (x, 0), (x, 200))
for y in range(0, 101, 5):
pg.draw.line(texture, (0, 0, 0), (0, y), (200, y))
# Render the text and use pure white as the color.
text_surface = FONT.render('Hello world!', True, (255, 255, 255))
frames = []
for i in range(5):
surf = text_surface.copy() # We need a fresh copy of the text.
# Now blit the texture onto the text surface and pass BLEND_RGB_MULT as
# the special_flags argument, so that only the opaque parts are affected.
# The y-position is shifted by -1 each iteration.
surf.blit(texture, (0, -1*i), special_flags=pg.BLEND_RGB_MULT)
frames.append(surf)
frame_counter = 0
frame_timer = 0
dt = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
frame_timer += dt # Add the passed time.
if frame_timer >= 150: # If 150 milliseconds have passed...
frame_timer = 0 # Reset the timer.
frame_counter += 1 # Increment the counter.
frame_counter %= len(frames) # Keep it in the correct range.
screen.fill(BG_COLOR)
# Now use `frame_counter` as the list index and blit the surface.
screen.blit(frames[frame_counter], (50, 170))
pg.display.flip()
dt = clock.tick(60) # `dt` is the passed time in milliseconds.
pg.quit()

Optimizing Pygame sprite images? [duplicate]

I'm having trouble with the framerate in my game. I've set it to 60 but it only goes to ~25fps. This was not an issue before displaying the background (was fine with only win.fill(WHITE)). Here is enough of the code to reproduce:
import os, pygame
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (50, 50)
pygame.init()
bg = pygame.image.load('images/bg.jpg')
FPS = pygame.time.Clock()
fps = 60
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
winW = 1227
winH = 700
win = pygame.display.set_mode((winW, winH))
win.fill(WHITE)
pygame.display.set_icon(win)
def redraw_window():
#win.fill(WHITE)
win.blit(bg, (0, 0))
win.blit(text_to_screen('FPS: {}'.format(FPS.get_fps()), BLUE), (25, 50))
pygame.display.update()
def text_to_screen(txt, col):
font = pygame.font.SysFont('Comic Sans MS', 25, True)
text = font.render(str(txt), True, col)
return text
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw_window()
FPS.tick(fps)
pygame.quit()
Ensure that the background Surface has the same format as the display Surface. Use convert() to create a Surface that has the same pixel format. That should improve the performance, when the background is blit to the display, because the formats are compatible and blit do not have to do an implicit transformation.
bg = pygame.image.load('images/bg.jpg').convert()
Furthermore, it is sufficient to create the font once, rather than every time when a text is drawn. Move font = pygame.font.SysFont('Comic Sans MS', 25, True) to the begin of the application (somewhere after pygame.init() and before the main application loop)
Instead use screen.blit(pygame.image.load(picture.png))
Just image = pygame.image.load(picture.png) then screen.blit(image)
( if you keep loading your pictures continuously it will get lag )

How to let pygame text input detect the key in Pygame? [duplicate]

This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
Closed 5 years ago.
I'm doing a project that using Python and Pygame. I want to ask some question about the key in Pygame.
Thank you Shubhitgarg. I use his/her suggestions(use pygame_textinput), it succeed. Now I want to change the text input position with pressed an enter, but it can't detect the enter. How can I fix it? My real code:
# installing package
import pygame
from pygame import *
import pygame_textinput
pygame.init()
# colour settings
red = (255, 0, 0)
green = (0, 255, 0)
grass_green = (112, 173, 71)
blue = (0, 0, 255)
yellow = (255, 255, 0)
white = (255, 255, 255)
black = (0, 0, 0)
# screen settings
window = pygame.display.set_mode((680, 600))
window.fill(grass_green)
pygame.display.flip()
# font settings
default_font = pygame.font.get_default_font()
big_font = pygame.font.Font(default_font, 96)
font_a = pygame.font.Font(default_font, 50)
font_b = pygame.font.Font(default_font, 30)
font_c = pygame.font.Font(default_font, 18)
# text input settings
textinput = pygame_textinput.TextInput("freeansbold.ttf", 96, True, black, white, 400, 35)
# timer
start = pygame.time.get_ticks()
# text
please_guess_a_number = font_a.render("Please guess a number. ", 1, white)
text_range = font_c.render("from to", 1, white)
wrong_bigger = font_b.render("Sorry, You haven’t guess it rightly. Please try again.(The answer must be bigger.)", 1, white)
wrong_smaller = font_b.render("Sorry, You haven’t guess it rightly. Please try again.(The answer must be smaller.)", 1, white)
correct = font_b.render("Congratulations! You guess it correctly!!", 1, white)
# game
ask_you_to_set_range_1 = True
ask_you_to_set_range_2 = False
while True:
if ask_you_to_set_range_1:
window.blit(please_guess_a_number, (60, 80))
pygame.draw.rect(window, yellow, [60, 200, 230, 300])
pygame.draw.rect(window, yellow, [390, 200, 230, 300])
window.blit(text_range, (10, 550))
pygame.display.flip()
while True:
events = pygame.event.get()
textinput.update(events)
window.blit(textinput.get_surface(), (110, 300))
pygame.display.flip()
if ask_you_to_set_range_2:
while True:
events = pygame.event.get()
textinput.update(events)
window.blit(textinput.get_surface(), (440, 300))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if ask_you_to_set_range_1 and event.key == pygame.K_KP_ENTER:
ask_you_to_set_range_1 = False
ask_you_to_set_range_2 = True
if textinput.update(event):
num1 = textinput.get_text()
text1 = big_font.render(num1, 1, black)
window.blit(text1, (110, 300))
Can anyone teach me to solve it?
You see this https://github.com/ShubhitGarg/pygame-text-input .
You can import this and use the text_input class and blit it on the same or next page
Use this
textinput = pygame_textinput.TextInput()
while True:
screen.fill((225, 225, 225))
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
# Feed it with events every frame
textinput.update(events)
# Blit its surface onto the screen
screen.blit(textinput.get_surface(), (10, 10))
pygame.display.update()

What can I improve considering these cProfile results? [duplicate]

I'm having trouble with the framerate in my game. I've set it to 60 but it only goes to ~25fps. This was not an issue before displaying the background (was fine with only win.fill(WHITE)). Here is enough of the code to reproduce:
import os, pygame
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (50, 50)
pygame.init()
bg = pygame.image.load('images/bg.jpg')
FPS = pygame.time.Clock()
fps = 60
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
winW = 1227
winH = 700
win = pygame.display.set_mode((winW, winH))
win.fill(WHITE)
pygame.display.set_icon(win)
def redraw_window():
#win.fill(WHITE)
win.blit(bg, (0, 0))
win.blit(text_to_screen('FPS: {}'.format(FPS.get_fps()), BLUE), (25, 50))
pygame.display.update()
def text_to_screen(txt, col):
font = pygame.font.SysFont('Comic Sans MS', 25, True)
text = font.render(str(txt), True, col)
return text
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw_window()
FPS.tick(fps)
pygame.quit()
Ensure that the background Surface has the same format as the display Surface. Use convert() to create a Surface that has the same pixel format. That should improve the performance, when the background is blit to the display, because the formats are compatible and blit do not have to do an implicit transformation.
bg = pygame.image.load('images/bg.jpg').convert()
Furthermore, it is sufficient to create the font once, rather than every time when a text is drawn. Move font = pygame.font.SysFont('Comic Sans MS', 25, True) to the begin of the application (somewhere after pygame.init() and before the main application loop)
Instead use screen.blit(pygame.image.load(picture.png))
Just image = pygame.image.load(picture.png) then screen.blit(image)
( if you keep loading your pictures continuously it will get lag )

How efficient is blitting a surface with a colorkey in pygame? [duplicate]

I'm having trouble with the framerate in my game. I've set it to 60 but it only goes to ~25fps. This was not an issue before displaying the background (was fine with only win.fill(WHITE)). Here is enough of the code to reproduce:
import os, pygame
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (50, 50)
pygame.init()
bg = pygame.image.load('images/bg.jpg')
FPS = pygame.time.Clock()
fps = 60
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
winW = 1227
winH = 700
win = pygame.display.set_mode((winW, winH))
win.fill(WHITE)
pygame.display.set_icon(win)
def redraw_window():
#win.fill(WHITE)
win.blit(bg, (0, 0))
win.blit(text_to_screen('FPS: {}'.format(FPS.get_fps()), BLUE), (25, 50))
pygame.display.update()
def text_to_screen(txt, col):
font = pygame.font.SysFont('Comic Sans MS', 25, True)
text = font.render(str(txt), True, col)
return text
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw_window()
FPS.tick(fps)
pygame.quit()
Ensure that the background Surface has the same format as the display Surface. Use convert() to create a Surface that has the same pixel format. That should improve the performance, when the background is blit to the display, because the formats are compatible and blit do not have to do an implicit transformation.
bg = pygame.image.load('images/bg.jpg').convert()
Furthermore, it is sufficient to create the font once, rather than every time when a text is drawn. Move font = pygame.font.SysFont('Comic Sans MS', 25, True) to the begin of the application (somewhere after pygame.init() and before the main application loop)
Instead use screen.blit(pygame.image.load(picture.png))
Just image = pygame.image.load(picture.png) then screen.blit(image)
( if you keep loading your pictures continuously it will get lag )

Categories

Resources