Advertisement
Windspar

Pygame Font Play. Example Wave Text Include.

Feb 1st, 2023 (edited)
996
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.97 KB | Gaming | 0 0
  1. # Design for individual letters.
  2. # For each letter can be effected in different ways.
  3. # Effects like wave, fading, spinning, shooting away, and what ever else you can think of.
  4.  
  5. import string
  6.  
  7. from pygame import Color, Rect, Vector2, SRCALPHA
  8. from pygame.font import Font
  9. from pygame.sprite import Group, Sprite
  10.  
  11. # My Typewriter effect. Use with pygame.time.Timer
  12. class WriterText:
  13.     def __init__(self, pen, text, rpos, xspace=0):
  14.         self.pen = pen
  15.         self.rpos = rpos
  16.         self.text = text
  17.         self.xspace = xspace
  18.         self.length = 0
  19.         self.letters = pen.render_letters(text, rpos, xspace, True)
  20.  
  21.     def is_done(self):
  22.         return self.length == len(self.letters)
  23.  
  24.     def draw(self, surface):
  25.         for i in range(self.length):
  26.             self.letters[i].draw(surface)
  27.  
  28.     def render(self):
  29.         size = self.pen.get_rect(self.text[:self.length], self.xspace).size
  30.         surface = pygame.Surface(size, SRCALPHA)
  31.         for letter in self.letters[:self.length]:
  32.             pos = letter.rect.x - left, letter.rect.y - top
  33.             surface.blit(letter, pos)
  34.  
  35.         return surface
  36.  
  37.     def reset(self):
  38.         self.length = 0
  39.  
  40.     def update(self, timer):
  41.         if self.length < len(self.letters):
  42.             self.length += 1
  43.  
  44. class PenText:
  45.     def __init__(self, pen, text, rpos, xspace=0):
  46.         self.pen = pen
  47.         self.rpos = rpos
  48.         self.text = text
  49.         self.xspace = 0
  50.         self.letters = pen.render_letters(text, rpos, xspace)
  51.  
  52.     def draw(self, surface):
  53.         self.letters.draw(surface)
  54.  
  55.     def render(self):
  56.         size = self.pen.get_rect(self.text, self.xspace).size
  57.         surface = pygame.Surface(size, SRCALPHA)
  58.         for letter in self.letters:
  59.             pos = letter.rect.x - left, letter.rect.y - top
  60.             surface.blit(letter, pos)
  61.  
  62.         return surface
  63.  
  64.     def set_text(self, text):
  65.         self.text = text
  66.         self.letters = self.pen.write(text, self.rpos)
  67.  
  68. class LetterSprite(Sprite):
  69.     def __init__(self, pos, letter, rect):
  70.         super().__init__()
  71.         self.center = Vector2(rect.center)
  72.         self.origin = rect.center
  73.         self.image = letter
  74.         self.rect = rect
  75.         self.pos = pos
  76.  
  77.     def draw(self, surface):
  78.         surface.blit(self.image, self.rect)
  79.  
  80.     # move(x, y) or tuple, list, vector.
  81.     def move(self, *args):
  82.         if len(args) == 1:
  83.             self.center += args[0]
  84.         else:
  85.             self.center += args
  86.  
  87.         self.rect.center = self.center
  88.  
  89.     def origin_move(self, *args):
  90.         self.center = Vector2(self.origin)
  91.         self.move(*args)
  92.  
  93. class Pen:
  94.     def __init__(self, fontname, size, color, bcolor=None, allow_letters=False):
  95.         self.font = Font(fontname, size)
  96.         self.color = color
  97.         self.bcolor = bcolor
  98.         self.allow_letters = allow_letters
  99.         if allow_letters:
  100.             self._create_letters(color, bcolor)
  101.  
  102.     def _create_letters(self, color, bcolor):
  103.         self._letters = {}
  104.         for l in string.printable:
  105.             if l != ' ':
  106.                 self._letters[l] = self.font.render(l, 1, color, bcolor)
  107.  
  108.     def create_letters(self):
  109.         self._create_letters(self.color, self.bcolor)
  110.  
  111.     def get_rect(self, text, xspace):
  112.         rect = Rect((0, 0), self.font.size(text))
  113.         rect.w += xspace * (len(text) - 1)
  114.         return rect
  115.  
  116.     def render(self, text, color=None, bcolor=None):
  117.         if not color:
  118.             color = self.color
  119.  
  120.         if not bcolor:
  121.             bcolor = self.bcolor
  122.  
  123.         return self.font.render(text, 1, color, bcolor)
  124.  
  125.     def render_letters(self, text, rposition, xspace=0, use_list=False):
  126.         if not self.allow_letters:
  127.             return None
  128.  
  129.         if not use_list:
  130.             letters = Group()
  131.         else:
  132.             letters = []
  133.  
  134.         rect = self.get_rect(text, xspace)
  135.         rposition.apply(rect)
  136.         x, y = rect.topleft
  137.         xoffset = 0
  138.         offset = 0
  139.  
  140.         for i, letter in enumerate(text):
  141.             if letter != ' ':
  142.                 image = self._letters[letter]
  143.                 rect = image.get_rect(topleft=(x, y))
  144.                 sprite = LetterSprite(i, image, rect)
  145.                 if not use_list:
  146.                     letters.add(sprite)
  147.                 else:
  148.                     letters.append(sprite)
  149.  
  150.             xoffset += xspace
  151.             spacing = self.font.size(text[:i + 1])[0] + xoffset
  152.             x += spacing - offset
  153.             offset = spacing
  154.  
  155.         return letters
  156.  
  157.     # xspace is just to increase spacing between letters.
  158.     def render_text(self, text, rpos, xspace=0):
  159.         if not self.allow_letters:
  160.             return None
  161.  
  162.         return PenText(self, text, rpos, xspace)
  163.  
  164.     # xspace is just to increase spacing between letters.
  165.     def render_writer(self, text, rpos, xspace=0):
  166.         if not self.allow_letters:
  167.             return None
  168.  
  169.         return WriterText(self, text, rpos, xspace)
  170.  
  171.     # Use to change prerender letters color.
  172.     # Will change all text that uses this pen prerender letters.
  173.     def set_color(self, color):
  174.         self.color = color
  175.         if self.allow_letters:
  176.             color = Color(color)
  177.             letters = self._letters
  178.             for key in letters:
  179.                 sx, sy = letters[key].get_size()
  180.                 for x in range(sx):
  181.                     for y in range(sy):
  182.                         ocolor = letters[key].get_at((x, y))
  183.                         color.a = ocolor.a
  184.                         letters[key].set_at((x, y), color)
  185.  
  186. # Just for setting position by rect.
  187. class RectPosition:
  188.     # Creation
  189.     @classmethod
  190.     def from_rect(cls, rect, rect_anchor='center', anchor='center'):
  191.         return cls(getattr(rect, rect_anchor), anchor)
  192.  
  193.     def __init__(self, position, anchor='topleft'):
  194.         self.position = position
  195.         self.anchor = anchor
  196.  
  197.     # Methods
  198.     def apply(self, rect):
  199.         setattr(rect, self.anchor, self.position)
  200.  
  201.     def reposition(self, position, rect):
  202.         x, y = self.position
  203.         self.position = position[0] + x, position[1] + y
  204.         self.apply(rect)
  205.  
  206. # Example
  207. import pygame
  208. from math import sin, radians
  209.  
  210. WAVE = pygame.event.custom_type()
  211.  
  212. class Wave:
  213.     def __init__(self, pen_text, flux, height, offset=0):
  214.         self.pen_text = pen_text
  215.         self.flux = flux / (len(pen_text.text) - 1)
  216.         self.height = height
  217.  
  218.     def __call__(self, offset=0):
  219.         for letter in self.pen_text.letters:
  220.             y = int(sin(radians((letter.pos + offset) * self.flux)) * self.height)
  221.             letter.origin_move(0, y)
  222.  
  223. def main():
  224.     pygame.init()
  225.     pygame.display.set_caption("Example")
  226.     surface = pygame.display.set_mode((500, 500))
  227.     rect = surface.get_rect()
  228.     clock = pygame.time.Clock()
  229.     fps = 60
  230.  
  231.     # Example Variables
  232.     pen = Pen(None, 30, 'snow', allow_letters=True)
  233.     word = 'Hello, Hello World'
  234.     pen_text = pen.render_text(word, RectPosition(rect.center, 'center'))
  235.     # flux: -180, 180, -360, 360 . Just common degrees
  236.     wave_effect = Wave(pen_text, 360, 40)
  237.     colors = 'white', 'firebrick', 'darkgreen', 'dodgerblue', 'purple'
  238.     color_n = 0
  239.  
  240.     pygame.time.set_timer(WAVE, 120)
  241.     offset = 0
  242.     wave_effect(offset)
  243.  
  244.     running = True
  245.     while running:
  246.         for event in pygame.event.get():
  247.             if event.type == WAVE:
  248.                 offset = (offset + 1) % len(pen_text.text)
  249.                 wave_effect(offset)
  250.             elif event.type == pygame.KEYDOWN:
  251.                 if event.key == pygame.K_SPACE:
  252.                     color_n = (color_n + 1) % len(colors)
  253.                     color = colors[color_n]
  254.                     pen.set_color(color)
  255.             elif event.type == pygame.QUIT:
  256.                 running = False
  257.  
  258.         surface.fill('black')
  259.         pen_text.draw(surface)
  260.         pygame.display.flip()
  261.         clock.tick(fps)
  262.  
  263.     pygame.quit()
  264.  
  265. main()
  266.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement