Pygame Sprite Text

Sprite Text

from pygame import Rect
from pygame.sprite import Sprite

# Simple sprite text.
# @param anchor : 'topleft', 'topright', 'bottomright', 'bottomleft', 'center
class Text(Sprite):
    def __init__(self, text, font, color, position, anchor="topleft"):
        Sprite.__init__(self)
        self.anchor = anchor
        self.color = color
        self.font = font

        self.rect = Rect(0, 0, 0, 0)
        setattr(self.rect, anchor, position)

        self.render_text(text)


    def render_text(self, text):
        self.image = self.font.render(text, 1, self.color)

        position = getattr(self.rect, self.anchor)
        self.rect = self.image.get_rect()
        setattr(self.rect, self.anchor, position)

# A clickable hilight sprite text.
# @param anchor : 'topleft', 'topright', 'bottomright', 'bottomleft', 'center
class ClickText(Sprite):
    def __init__(self, text, font, color, hcolor, position, anchor="topleft"):
        Sprite.__init__(self)
        self.anchor = anchor
        self.hcolor = hcolor
        self.hover = False
        self.color = color
        self.font = font

        self.rect = Rect(0, 0, 0, 0)
        setattr(self.rect, anchor, position)
        self.render_text(text)

    def set_callback(self, callback, user_data=None):
        self.callback = callback
        self.user_data = user_data

    @property
    def image(self):
        if self.hover:
            return self.hover_image
        return self.normal_image

    def render_text(self, text):
        self.normal_image = self.font.render(text, 1, self.color)
        self.hover_image = self.font.render(text, 1, self.hcolor)

        position = getattr(self.rect, self.anchor)
        self.rect = self.normal_image.get_rect()
        setattr(self.rect, self.anchor, position)

    def on_mousemotion(self, event):
        self.hover = self.rect.collidepoint(event.pos)

    def on_click(self, event):
        if event.button == 1:
            if self.rect.collidepoint(event.pos):
                self.callback(self)

Example

import pygame
import itertools
from statemachine import State
from pygame.sprite import Group
from sprite_text import Text, ClickText

class Example(State):
    def __init__(self):
        self.sprites = Group()
        self.click_sprites = Group()
        font = pygame.font.Font(None, 36)
        position = State.machine.rect.centerx, 40
        color = pygame.Color("lawngreen")
        title = Text("Sprite Text Example", font, color, position, "center")
        title.add(self.sprites)

        self.font = pygame.font.Font(None, 24)
        position = 400, 150
        self.text = Text("Nothing been click", self.font, color, position)
        self.text.add(self.sprites)

        y = itertools.count(150, 25)
        self.add_click_text("Click Me", (50, next(y)), "Got you to click me")
        self.add_click_text("Don't Click Me", (50, next(y)),
                            "Can't you read. Don't click me again")
        self.add_click_text("Click Me Please", (50, next(y)),
                            "I just wanted to be clicked")

    def add_click_text(self, text, position, user_data):
        color = pygame.Color("slateblue")
        hcolor = pygame.Color("dodgerblue")
        text = ClickText(text, self.font, color, hcolor, position)
        text.set_callback(self.on_textclick, user_data)
        text.add(self.sprites, self.click_sprites)

    def on_textclick(self, text):
        self.text.render_text(text.user_data)

    def on_draw(self, surface):
        surface.fill(pygame.Color("black"))
        self.sprites.draw(surface)

    def on_event(self, event):
        if event.type == pygame.MOUSEMOTION:
            for text in self.click_sprites:
                text.on_mousemotion(event)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            for text in self.click_sprites:
                text.on_click(event)
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                State.machine.running = False
        elif event.type == pygame.QUIT:
            State.machine.running = False

if __name__ == "__main__":
    pygame.init()
    State.machine_setup("Sprite Text Example", 800, 600, True)
    State.machine.flip(Example())
    State.machine.mainloop()