Windspar

Pygame Pen. Render characters once for faster changing text.

Nov 11th, 2025 (edited)
371
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.43 KB | Gaming | 0 0
  1. import string
  2. from pygame import Rect
  3. from pygame.sprite import Sprite, Group
  4. from pygame.font import Font
  5.  
  6. def color_wash(image, color):
  7.     if not isinstance(color, pygame.Color):
  8.         color = pygame.Color(color)
  9.        
  10.     width, height = image.get_size()
  11.     for x in range(width):
  12.         for y in range(height):
  13.             pcolor = image.get_at((x, y))
  14.             color.a = pcolor.a
  15.             image.set_at((x, y), color)
  16.  
  17. PRINTABLE = string.ascii_letters + string.punctuation + string.digits
  18.  
  19. class Character(Sprite):
  20.     def __init__(self, image):
  21.         super().__init__()
  22.         self.image = image
  23.         self.rect = image.get_rect()
  24.  
  25. class Pen:
  26.     @classmethod
  27.     def font(cls, fontname, size, color, printable=PRINTABLE):
  28.         font = Font(fontname, size)
  29.         return cls(font, color, printable)
  30.  
  31.     def __init__(self, font, color, printable=PRINTABLE):
  32.         self.printable = printable
  33.         self.characters = {}
  34.         self.advance = {}
  35.         self.font = font
  36.         self._character_build(color)
  37.  
  38.     def _character_build(self, color):
  39.         for char in self.printable:
  40.             self.characters[char] = self.font.render(char, 1, color)
  41.  
  42.         printable_space = self.printable + " "
  43.         for char in printable_space:
  44.             result = {}
  45.             for key in printable_space:
  46.                 text = char + key
  47.                 adv = self.font.size(text)[0]
  48.                 base = self.font.size(key)[0]
  49.                 result[key] = adv - base
  50.  
  51.             self.advance[char] = result
  52.  
  53.     def _line(self, text, position, padding, anchor, yline=0):
  54.         line = []
  55.         previous_char = None
  56.         width, height = self.font.size(text)
  57.         rect = Rect(0, 0, width + padding * len(text) - padding, height)
  58.         setattr(rect, anchor, position)
  59.         xpos, ypos = rect.topleft
  60.  
  61.         for enumx, char in enumerate(text):
  62.             if char in self.printable:
  63.                 if previous_char:
  64.                     xpos += self.advance[previous_char][char] + padding
  65.  
  66.                 images = self.characters[char]
  67.                 sprite = Character(images)
  68.                 sprite.rect.topleft = xpos, ypos
  69.                 line.append(sprite)
  70.                 previous_char = char
  71.             elif char == " ":
  72.                 if previous_char:
  73.                     xpos += self.advance[previous_char][char] + padding
  74.  
  75.                 previous_char = char
  76.  
  77.         return line
  78.  
  79.     def render(self, text, position, padding=(0, 0), anchor='topleft'):
  80.         lines = self.write(text, position, padding, anchor)
  81.         result = Group()
  82.         for line in lines:
  83.             result.add(line)
  84.  
  85.         return result
  86.  
  87.     def set_color(self, color):
  88.         for image in self.characters.values():
  89.             color_wash(image, color)
  90.  
  91.     def write(self, text, position, padding=(0, 0), anchor='topleft'):
  92.         if text.count('\n') > 0:
  93.             lines = []
  94.             xpos, ypos = position
  95.             text_lines = text.split('\n')
  96.             linesize = self.font.get_linesize() + padding[1]
  97.  
  98.             for yline, text_line in enumerate(text_lines):
  99.                 pos = xpos, ypos
  100.                 line = self._line(text_line, pos, padding[0], anchor, yline)
  101.                 lines.append(line)
  102.                 ypos += linesize
  103.  
  104.             return lines
  105.         else:
  106.             return [self._line(text, position, padding[0], anchor, 0)]
  107.  
Tags: python
Advertisement
Add Comment
Please, Sign In to add comment