Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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 :)

like image 414
ChewyCarrot Avatar asked May 03 '18 23:05

ChewyCarrot


1 Answers

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()
like image 54
skrx Avatar answered Oct 23 '22 03:10

skrx