Native pygame-ce game with fully procedural pixel art and chiptune audio (no asset files). Pure-logic physics module with flipper angular momentum, plus headless autoplay/screenshot/probe dev tools.
117 lines
5.0 KiB
Python
117 lines
5.0 KiB
Python
"""Tiny hand-rolled 5x5 pixel bitmap font, rendered chunky for an 8-bit look."""
|
|
|
|
import pygame
|
|
|
|
|
|
GLYPHS = {
|
|
"A": [".###.", "#...#", "#####", "#...#", "#...#"],
|
|
"B": ["####.", "#...#", "####.", "#...#", "####."],
|
|
"C": [".###.", "#....", "#....", "#....", ".###."],
|
|
"D": ["####.", "#...#", "#...#", "#...#", "####."],
|
|
"E": ["#####", "#....", "####.", "#....", "#####"],
|
|
"F": ["#####", "#....", "####.", "#....", "#...."],
|
|
"G": [".###.", "#....", "#.###", "#...#", ".###."],
|
|
"H": ["#...#", "#...#", "#####", "#...#", "#...#"],
|
|
"I": ["#####", "..#..", "..#..", "..#..", "#####"],
|
|
"J": ["..###", "...#.", "...#.", "#..#.", ".##.."],
|
|
"K": ["#...#", "#..#.", "###..", "#..#.", "#...#"],
|
|
"L": ["#....", "#....", "#....", "#....", "#####"],
|
|
"M": ["#...#", "##.##", "#.#.#", "#...#", "#...#"],
|
|
"N": ["#...#", "##..#", "#.#.#", "#..##", "#...#"],
|
|
"O": [".###.", "#...#", "#...#", "#...#", ".###."],
|
|
"P": ["####.", "#...#", "####.", "#....", "#...."],
|
|
"Q": [".###.", "#...#", "#...#", "#..#.", ".##.#"],
|
|
"R": ["####.", "#...#", "####.", "#..#.", "#...#"],
|
|
"S": [".###.", "#....", ".###.", "....#", "####."],
|
|
"T": ["#####", "..#..", "..#..", "..#..", "..#.."],
|
|
"U": ["#...#", "#...#", "#...#", "#...#", ".###."],
|
|
"V": ["#...#", "#...#", "#...#", ".#.#.", "..#.."],
|
|
"W": ["#...#", "#...#", "#.#.#", "##.##", "#...#"],
|
|
"X": ["#...#", ".#.#.", "..#..", ".#.#.", "#...#"],
|
|
"Y": ["#...#", ".#.#.", "..#..", "..#..", "..#.."],
|
|
"Z": ["#####", "...#.", "..#..", ".#...", "#####"],
|
|
"0": [".###.", "#..##", "#.#.#", "##..#", ".###."],
|
|
"1": ["..#..", ".##..", "..#..", "..#..", ".###."],
|
|
"2": ["####.", "....#", ".###.", "#....", "#####"],
|
|
"3": ["####.", "....#", ".###.", "....#", "####."],
|
|
"4": ["#...#", "#...#", "#####", "....#", "....#"],
|
|
"5": ["#####", "#....", "####.", "....#", "####."],
|
|
"6": [".###.", "#....", "####.", "#...#", ".###."],
|
|
"7": ["#####", "....#", "...#.", "..#..", ".#..."],
|
|
"8": [".###.", "#...#", ".###.", "#...#", ".###."],
|
|
"9": [".###.", "#...#", ".####", "....#", ".###."],
|
|
" ": [".....", ".....", ".....", ".....", "....."],
|
|
".": [".....", ".....", ".....", "..##.", "..##."],
|
|
",": [".....", ".....", "..#..", "..#..", ".#..."],
|
|
"!": ["..#..", "..#..", "..#..", ".....", "..#.."],
|
|
"?": [".###.", "#...#", "..#..", ".....", "..#.."],
|
|
"'": ["..#..", "..#..", ".....", ".....", "....."],
|
|
'"': [".#.#.", ".#.#.", ".....", ".....", "....."],
|
|
":": [".....", "..#..", ".....", "..#..", "....."],
|
|
";": [".....", "..#..", ".....", "..#..", ".#..."],
|
|
"-": [".....", ".....", "#####", ".....", "....."],
|
|
"+": ["..#..", "..#..", "#####", "..#..", "..#.."],
|
|
"*": ["#...#", ".#.#.", "..#..", ".#.#.", "#...#"],
|
|
"/": ["....#", "...#.", "..#..", ".#...", "#...."],
|
|
"=": [".....", "#####", ".....", "#####", "....."],
|
|
"<": ["...#.", "..#..", ".#...", "..#..", "...#."],
|
|
">": [".#...", "..#..", "...#.", "..#..", ".#..."],
|
|
"(": ["...#.", "..#..", ".#...", "..#..", "...#."],
|
|
")": [".#...", "..#..", "...#.", "..#..", ".#..."],
|
|
"~": [".....", ".#.#.", ".#.#.", ".....", "....."],
|
|
"|": ["..#..", "..#..", "..#..", "..#..", "..#.."],
|
|
"%": ["##..#", "##.#.", "..#..", ".#.##", "#..##"],
|
|
"&": [".##..", "#..#.", ".#...", "#.#.#", ".##.#"],
|
|
"@": [".###.", "#.#.#", "#.###", "#....", ".###."],
|
|
"#": [".#.#.", "#####", ".#.#.", "#####", ".#.#."],
|
|
"^": ["..#..", ".#.#.", "#...#", ".....", "....."],
|
|
"_": [".....", ".....", ".....", ".....", "#####"],
|
|
}
|
|
|
|
_text_cache = {}
|
|
|
|
|
|
def text_width(text, scale=1, spacing=1):
|
|
if not text:
|
|
return 0
|
|
return (len(text) * 5 + (len(text) - 1) * spacing) * scale
|
|
|
|
|
|
def render_text(text, color, scale=1, spacing=1, shadow=None):
|
|
"""Return a Surface with the pixel text drawn."""
|
|
key = (text, color, scale, spacing, shadow)
|
|
if key in _text_cache:
|
|
return _text_cache[key]
|
|
w = text_width(text, scale, spacing)
|
|
h = 5 * scale
|
|
surf = pygame.Surface((w, h), pygame.SRCALPHA)
|
|
if shadow is not None:
|
|
_draw_into(surf, text, shadow, scale, spacing, (scale, scale))
|
|
_draw_into(surf, text, color, scale, spacing, (0, 0))
|
|
_text_cache[key] = surf
|
|
return surf
|
|
|
|
|
|
def _draw_into(surf, text, color, scale, spacing, off):
|
|
x0 = off[0]
|
|
for ch in text.upper():
|
|
g = GLYPHS.get(ch, GLYPHS[" "])
|
|
for row in range(5):
|
|
for col in range(5):
|
|
if g[row][col] == "#":
|
|
surf.fill(color, (x0 + col * scale, off[1] + row * scale, scale, scale))
|
|
x0 += (5 + spacing) * scale
|
|
|
|
|
|
def draw_text(surf, x, y, text, color, scale=1, spacing=1, align="left", shadow=(20, 12, 40, 180)):
|
|
"""Draw text. align in {'left','center','right'}. Shadow color or None."""
|
|
t = render_text(text, color, scale, spacing, shadow)
|
|
if align == "center":
|
|
x -= t.get_width() // 2
|
|
elif align == "right":
|
|
x -= t.get_width()
|
|
surf.blit(t, (round(x), round(y)))
|
|
return t.get_width(), t.get_height()
|
|
|
|
|