Initial commit
This commit is contained in:
72
game/assets.py
Normal file
72
game/assets.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Sprite loading with graceful placeholders.
|
||||
|
||||
Every drawable in the game asks the AssetStore for a surface by name. If a PNG
|
||||
named ``<name>.png`` exists in the assets directory it is loaded and scaled to
|
||||
the requested size; otherwise a labeled colored rectangle is drawn instead, so
|
||||
the game is fully playable before any art exists.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
|
||||
from . import settings
|
||||
|
||||
|
||||
class AssetStore:
|
||||
def __init__(self, assets_dir):
|
||||
self.assets_dir = assets_dir
|
||||
self._raw = {} # name -> original loaded Surface (or None if missing)
|
||||
self._cache = {} # (name, w, h) -> scaled Surface
|
||||
self._font = None
|
||||
|
||||
def _font_for(self, h):
|
||||
# Lazily build a font sized to the tile so placeholder labels fit.
|
||||
size = max(10, int(h * 0.5))
|
||||
return pygame.font.SysFont("consolas,menlo,monospace", size, bold=True)
|
||||
|
||||
def _load_raw(self, name):
|
||||
if name in self._raw:
|
||||
return self._raw[name]
|
||||
path = os.path.join(self.assets_dir, name + ".png")
|
||||
surf = None
|
||||
if os.path.isfile(path):
|
||||
try:
|
||||
surf = pygame.image.load(path).convert_alpha()
|
||||
except pygame.error:
|
||||
surf = None
|
||||
self._raw[name] = surf
|
||||
return surf
|
||||
|
||||
def get(self, name, w, h, angle=0):
|
||||
"""Return a Surface of exactly (w, h) for the given sprite name,
|
||||
optionally rotated counter-clockwise by ``angle`` degrees first (used to
|
||||
point directional sprites like spikes the right way)."""
|
||||
w, h = int(w), int(h)
|
||||
angle %= 360
|
||||
key = (name, w, h, angle)
|
||||
if key in self._cache:
|
||||
return self._cache[key]
|
||||
|
||||
raw = self._load_raw(name)
|
||||
if raw is not None:
|
||||
if angle:
|
||||
raw = pygame.transform.rotate(raw, angle)
|
||||
# Nearest-neighbour keeps the pixel-art sprites crisp at any size.
|
||||
surf = pygame.transform.scale(raw, (w, h))
|
||||
else:
|
||||
surf = self._make_placeholder(name, w, h)
|
||||
|
||||
self._cache[key] = surf
|
||||
return surf
|
||||
|
||||
def _make_placeholder(self, name, w, h):
|
||||
color, label = settings.PLACEHOLDERS.get(name, ((200, 60, 200), "?"))
|
||||
surf = pygame.Surface((w, h), pygame.SRCALPHA)
|
||||
surf.fill(color)
|
||||
# A subtle border helps distinguish adjacent tiles of the same color.
|
||||
pygame.draw.rect(surf, (0, 0, 0, 90), surf.get_rect(), max(1, w // 16))
|
||||
if label:
|
||||
font = self._font_for(h)
|
||||
text = font.render(label, True, (15, 15, 20))
|
||||
surf.blit(text, text.get_rect(center=(w // 2, h // 2)))
|
||||
return surf
|
||||
Reference in New Issue
Block a user