# Pygskin
A collection of useful functions and classes for Pygame
## [`animate` function](pygskin/animation.py)
Animation generator function which takes a list of frames or mapping of
quotients (0.0 - 1.0) to keyframes and a function that returns a quotient, and
returns an generator that returns frames.
```python
anim = animate([image1, image2], timer.quotient)
screen.blit(next(anim))
```
## [`Assets` class](pygskin/assets.py)
Provides attribute access to asset files and batch loading
```python
assets = Assets()
screen.blit(assets.player)
assets.player_spawn_sfx.play()
```
## [`Camera` class](pygskin/camera.py)
A camera class for scrolling and zooming a surface.
```python
camera = Camera(screen.get_rect(), clamp=world_map.get_rect())
camera.view.fill("black")
sprite_group.draw(camera)
camera.zoom = 2.4
camera.draw(screen)
```
## [`Timer` class](pygskin/clock.py)
A countdown timer dataclass. Can be used with the `animate` function.
```python
timer = Timer(3000) # 3 seconds
timer.tick()
if timer.finished:
timer.elapsed = 0 # loop
```
## [`iter_dialogue` function](pygskin/dialogue.py)
Generator function for stepping through a dialogue script parsed from a JSON or
YAML file.
```python
context = {}
dialogue = iter_dialogue(
assets.act1_scene1,
context,
speak=speak,
)
def main_loop(screen, events, quit):
if action := next(dialogue, None):
action()
```
## [`Direction` enum](pygskin/direction.py)
Enum for up/down/left/right directions
```python
direction = Direction.UP
if direction in Direction.VERTICAL:
rect.move_ip(direction.vector)
```
## [`easing` module](pygskin/easing.py)
A selection of easing functions for use with interpolation. Can be used with the
`animate` and `make_color_gradient` functions.
## [`Component` class](pygskin/ecs.py)
A minimal ECS implementation.
```python
class Velocity(Component[Vector2]): ...
class Position(Component[Vector2]): ...
def apply_velocity_system() -> None:
for id, velocity in Velocity.components.items():
pos = Position.components[id]
pos += velocity
@dataclass
class Entity:
pos: Position = Position()
velocity: Velocity = Velocity()
entities = [Entity(pos=Vector2(0, 0), velocity=Vector2(1, 1)])
apply_velocity_system()
```
## [`bind` function](pygskin/func.py)
Partial function application with one or more argument placeholders at arbitrary
positions.
```python
foos = filter(bind(isinstance, ..., Foo), items)
```
## [`run_game` function](pygskin/game.py)
Pygbag compatible game loop.
```python
def main_loop(screen, events, exit):
screen.fill(random.choice(pygame.color.THECOLORS.values()))
for event in events:
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
exit()
if __name__ == '__main__':
run_game(Window("My Game", (WIDTH, HEIGHT)), main_loop)
```
## [`make_color_gradient` function](pygskin/gradient.py)
Generate a color gradient between two colors.
```python
sky_image = make_color_gradient(screen.size, "white", "blue")
screen.blit(sky_image)
```
## [`imgui` module](pygskin/imgui.py)
Immediate mode GUI.
```python
gui = imgui.IMGUI()
def main_loop(screen, events, exit):
with imgui.render(gui, screen) as render:
if render(imgui.button("Quit"), center=(100, 200)):
exit()
```
## [`map_inputs_to_actions` function](pygskin/input.py)
Map input events to actions. Enables user-defined key bindings.
```python
keyboard_controls = {
"jump": Event(pg.KEYDOWN, key=pg.K_UP),
"duck": Event(pg.KEYDOWN, key=pg.K_DOWN),
"quit": Event(pg.KEYDOWN, key=pg.K_ESCAPE),
}
for action in map_inputs_to_actions(
keyboard_controls,
pygame.event.get(),
):
if action == "jump":
player.jump()
if action == "duck":
player.duck()
if action == "quit":
exit()
```
## [`lazy` class](pygskin/lazy.py)
Lazy loading object proxy. Works like a partial function application for
objects.
```python
image = lazy(pygame.image.load, "foo.png"))
screen.blit(image)
```
## [`scroll_parallax_layers` function](pygskin/parallax.py)
Scroll parallax layers at different rates.
```python
background = LayeredUpdates()
background.add(assets.sky, layer=0)
background.add(assets.mountains, layer=1)
background.add(assets.trees, layer=2)
scroll_parallax_layers(
(vx, vy),
background.layers,
background.get_sprites_from_layer,
{0: 0, 1: 1.5, 2: 2.0},
)
```
## [`channel` function](pygskin/pubsub.py)
Simple pubsub implementation.
```python
foo = channel()
foo.subscribe(lambda x: print(f"subscriber 1: {x}"))
foo("bar")
```
## [`get_rect_attrs` function](pygskin/rect.py)
Filter rect attributes (eg `top`, `center`, `size`) from a dictionary. Useful
for passing kwargs to `pygame.Rect.move_to` or `pygame.Surface.get_rect`.
```python
def foo(image: Surface, **kwargs):
image_rect = image.get_rect(**get_rect_attrs(kwargs))
```
## [`add_padding` function](pygskin/rect.py)
Add padding of varying amounts to a Rect.
```python
top, right, bottom, left = [100, 50, 10, 5]
padded, rect = add_padding(Rect(0, 0, 10, 10), [top, right, bottom, left])
assert padded.size == (120, 65)
assert rect.topleft == (5, 100)
```
## [`grid` function](pygskin/rect.py)
Divide a Rect into a specified number of rows and columns, and return a function
to access the cells by row/column index, or string aliases.
```python
get_cell = grid(
Rect(0, 0, 100, 100),
rows=2,
cols=2,
names={"nw": (0, 0), "ne": (1, 0), "sw": (0, 1), "se": (1, 1)},
)
assert get_cell("ne") == get_cell(1, 0) == Rect(50, 0, 50, 50)
```
## [`screen_manager` function](pygskin/screen.py)
Screen manager state machine.
```python
def main():
return screen_manager(
show_main_menu,
play_level,
)
def show_main_menu(surface, events, exit_screen):
surface.blit(assets.main_menu)
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
exit_screen()
if event.key == pygame.K_RETURN:
exit_screen(to=play_level)
def play_level(surface, events, exit_screen):
...
```
## [`shake` function](pygskin/shake.py)
Shake animation generator.
```python
rect = Rect(100, 100, 100, 100)
timer = Timer(3000)
shake_fn = shake()
def main_loop(screen, events, exit):
screen.fill("black")
timer.tick()
pygame.draw.rect(screen, "red", rect.move(shake_fn(timer.quotient())))
```
## [`spritesheet` function](pygskin/spritesheet.py)
Provides grid cell access to a spritesheet image.
```python
get_sprite = spritesheet(pygame.image.load("foo.png"), rows=3, cols=4)
screen.blit(get_sprite(2, 1))
walk_frames = [get_sprite(0, i) for i in range(4)]
walk_anim = animate(walk_frames, timer.quotient)
```
## [`draw_sprite_stack` function](pygskin/spritestack.py)
Draw a pseudo-3d sprite using sprite-stacking.
```python
draw_sprite_stack(
screen,
spritesheet(assets.player, rows=1, cols=8),
(100, 100),
spacing=3,
)
```
## [`statemachine` function](pygskin/statemachine.py)
State machine as generator.
## [`get_styles` function](pygskin/stylesheet.py)
Simple cascading style sheet engine. Filters styles by object type, class and id
attributes. Can be used with imgui module.
```yaml
# styles.yaml
"*":
color: black
background_color: grey
"#error":
background_color: red
```
```python
# cascading styles
stylesheet = partial(get_styles, assets.styles)
Foo = namedtuple("Foo", ["id"])
styles = stylesheet(Foo(id="error"))
assert styles["background_color"] == "red"
# use with imgui
with imgui.render(gui, surface, stylesheet) as render:
render(imgui.button("Click me!"), center=(100, 100))
```
## [`make_sprite` function](pygskin/surface.py)
Create a sprite from an image.
```python
player = make_sprite(assets.player, center=player_pos)
```
## [`rotate_surface` function](pygskin/surface.py)
Rotate a surface in place or around a specified point.
```python
rotated_image = rotate_surface(image, angle, center=(0, 0))
```
## [`to_snakecase` function](pygskin/text.py)
Convert CapWords to snake_case.
## [`speech_duration` function](pygskin/text.py)
Calculate rough speech duration in seconds.
## [`tile` function](pygskin/tile.py)
Generate a blit sequence to tile an image across a surface.
```python
screen.blits(tile(screen.get_rect(), assets.grass))
```
## [`angle_between` function](pygskin/vector.py)
Calculate the angle between two points.
Raw data
{
"_id": null,
"home_page": null,
"name": "Pygskin",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": "Andy Driver <andy@pagezero.net>",
"keywords": "framework, game, pygame",
"author": null,
"author_email": "Andy Driver <andy@pagezero.net>",
"download_url": "https://files.pythonhosted.org/packages/c2/a6/ae196469dd5c9f3606de7b90bdef9e79ebaa6912a48d695128abaf86d181/pygskin-0.3.0.tar.gz",
"platform": null,
"description": "# Pygskin\n\nA collection of useful functions and classes for Pygame\n\n## [`animate` function](pygskin/animation.py)\nAnimation generator function which takes a list of frames or mapping of\nquotients (0.0 - 1.0) to keyframes and a function that returns a quotient, and\nreturns an generator that returns frames.\n```python\nanim = animate([image1, image2], timer.quotient)\nscreen.blit(next(anim))\n```\n\n\n## [`Assets` class](pygskin/assets.py)\nProvides attribute access to asset files and batch loading\n```python\nassets = Assets()\nscreen.blit(assets.player)\nassets.player_spawn_sfx.play()\n```\n\n\n## [`Camera` class](pygskin/camera.py)\nA camera class for scrolling and zooming a surface.\n```python\ncamera = Camera(screen.get_rect(), clamp=world_map.get_rect())\ncamera.view.fill(\"black\")\nsprite_group.draw(camera)\ncamera.zoom = 2.4\ncamera.draw(screen)\n```\n\n## [`Timer` class](pygskin/clock.py)\nA countdown timer dataclass. Can be used with the `animate` function.\n```python\ntimer = Timer(3000) # 3 seconds\ntimer.tick()\nif timer.finished:\n timer.elapsed = 0 # loop\n```\n\n\n## [`iter_dialogue` function](pygskin/dialogue.py)\nGenerator function for stepping through a dialogue script parsed from a JSON or\nYAML file.\n```python\ncontext = {}\ndialogue = iter_dialogue(\n assets.act1_scene1,\n context,\n speak=speak,\n)\n\ndef main_loop(screen, events, quit):\n if action := next(dialogue, None):\n action()\n```\n\n\n## [`Direction` enum](pygskin/direction.py)\nEnum for up/down/left/right directions\n```python\ndirection = Direction.UP\nif direction in Direction.VERTICAL:\n rect.move_ip(direction.vector)\n```\n\n\n## [`easing` module](pygskin/easing.py)\nA selection of easing functions for use with interpolation. Can be used with the\n`animate` and `make_color_gradient` functions.\n\n\n## [`Component` class](pygskin/ecs.py)\nA minimal ECS implementation.\n```python\nclass Velocity(Component[Vector2]): ...\nclass Position(Component[Vector2]): ...\n\ndef apply_velocity_system() -> None:\n for id, velocity in Velocity.components.items():\n pos = Position.components[id]\n pos += velocity\n\n@dataclass\nclass Entity:\n pos: Position = Position()\n velocity: Velocity = Velocity()\n\nentities = [Entity(pos=Vector2(0, 0), velocity=Vector2(1, 1)])\n\napply_velocity_system()\n```\n\n\n## [`bind` function](pygskin/func.py)\nPartial function application with one or more argument placeholders at arbitrary\npositions.\n```python\nfoos = filter(bind(isinstance, ..., Foo), items)\n```\n\n\n## [`run_game` function](pygskin/game.py)\nPygbag compatible game loop.\n```python\ndef main_loop(screen, events, exit):\n screen.fill(random.choice(pygame.color.THECOLORS.values()))\n\n for event in events:\n if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n exit()\n\n\nif __name__ == '__main__':\n run_game(Window(\"My Game\", (WIDTH, HEIGHT)), main_loop)\n```\n\n\n## [`make_color_gradient` function](pygskin/gradient.py)\nGenerate a color gradient between two colors.\n```python\nsky_image = make_color_gradient(screen.size, \"white\", \"blue\")\nscreen.blit(sky_image)\n```\n\n\n## [`imgui` module](pygskin/imgui.py)\nImmediate mode GUI.\n```python\ngui = imgui.IMGUI()\n\ndef main_loop(screen, events, exit):\n with imgui.render(gui, screen) as render:\n if render(imgui.button(\"Quit\"), center=(100, 200)):\n exit()\n```\n\n\n## [`map_inputs_to_actions` function](pygskin/input.py)\nMap input events to actions. Enables user-defined key bindings.\n```python\nkeyboard_controls = {\n \"jump\": Event(pg.KEYDOWN, key=pg.K_UP),\n \"duck\": Event(pg.KEYDOWN, key=pg.K_DOWN),\n \"quit\": Event(pg.KEYDOWN, key=pg.K_ESCAPE),\n}\nfor action in map_inputs_to_actions(\n keyboard_controls,\n pygame.event.get(),\n):\n if action == \"jump\":\n player.jump()\n if action == \"duck\":\n player.duck()\n if action == \"quit\":\n exit()\n```\n\n\n## [`lazy` class](pygskin/lazy.py)\nLazy loading object proxy. Works like a partial function application for\nobjects.\n```python\nimage = lazy(pygame.image.load, \"foo.png\"))\nscreen.blit(image)\n```\n\n\n## [`scroll_parallax_layers` function](pygskin/parallax.py)\nScroll parallax layers at different rates.\n```python\nbackground = LayeredUpdates()\nbackground.add(assets.sky, layer=0)\nbackground.add(assets.mountains, layer=1)\nbackground.add(assets.trees, layer=2)\n\nscroll_parallax_layers(\n (vx, vy),\n background.layers,\n background.get_sprites_from_layer,\n {0: 0, 1: 1.5, 2: 2.0},\n)\n```\n\n\n## [`channel` function](pygskin/pubsub.py)\nSimple pubsub implementation.\n```python\nfoo = channel()\nfoo.subscribe(lambda x: print(f\"subscriber 1: {x}\"))\nfoo(\"bar\")\n```\n\n\n## [`get_rect_attrs` function](pygskin/rect.py)\nFilter rect attributes (eg `top`, `center`, `size`) from a dictionary. Useful\nfor passing kwargs to `pygame.Rect.move_to` or `pygame.Surface.get_rect`.\n```python\ndef foo(image: Surface, **kwargs):\n image_rect = image.get_rect(**get_rect_attrs(kwargs))\n```\n\n\n## [`add_padding` function](pygskin/rect.py)\nAdd padding of varying amounts to a Rect.\n```python\ntop, right, bottom, left = [100, 50, 10, 5]\npadded, rect = add_padding(Rect(0, 0, 10, 10), [top, right, bottom, left])\nassert padded.size == (120, 65)\nassert rect.topleft == (5, 100)\n```\n\n\n## [`grid` function](pygskin/rect.py)\nDivide a Rect into a specified number of rows and columns, and return a function\nto access the cells by row/column index, or string aliases.\n```python\nget_cell = grid(\n Rect(0, 0, 100, 100),\n rows=2,\n cols=2,\n names={\"nw\": (0, 0), \"ne\": (1, 0), \"sw\": (0, 1), \"se\": (1, 1)},\n)\nassert get_cell(\"ne\") == get_cell(1, 0) == Rect(50, 0, 50, 50)\n```\n\n\n## [`screen_manager` function](pygskin/screen.py)\nScreen manager state machine.\n```python\ndef main():\n return screen_manager(\n show_main_menu,\n play_level,\n )\n\ndef show_main_menu(surface, events, exit_screen):\n surface.blit(assets.main_menu)\n for event in events:\n if event.type == pygame.KEYDOWN:\n if event.key == pygame.K_ESCAPE:\n exit_screen()\n if event.key == pygame.K_RETURN:\n exit_screen(to=play_level)\n\ndef play_level(surface, events, exit_screen):\n ...\n```\n\n\n## [`shake` function](pygskin/shake.py)\nShake animation generator.\n```python\nrect = Rect(100, 100, 100, 100)\ntimer = Timer(3000)\nshake_fn = shake()\n\ndef main_loop(screen, events, exit):\n screen.fill(\"black\")\n timer.tick()\n pygame.draw.rect(screen, \"red\", rect.move(shake_fn(timer.quotient())))\n```\n\n\n## [`spritesheet` function](pygskin/spritesheet.py)\nProvides grid cell access to a spritesheet image.\n```python\nget_sprite = spritesheet(pygame.image.load(\"foo.png\"), rows=3, cols=4)\nscreen.blit(get_sprite(2, 1))\nwalk_frames = [get_sprite(0, i) for i in range(4)]\nwalk_anim = animate(walk_frames, timer.quotient)\n```\n\n\n## [`draw_sprite_stack` function](pygskin/spritestack.py)\nDraw a pseudo-3d sprite using sprite-stacking.\n```python\ndraw_sprite_stack(\n screen,\n spritesheet(assets.player, rows=1, cols=8),\n (100, 100),\n spacing=3,\n)\n```\n\n\n## [`statemachine` function](pygskin/statemachine.py)\nState machine as generator.\n\n\n## [`get_styles` function](pygskin/stylesheet.py)\nSimple cascading style sheet engine. Filters styles by object type, class and id\nattributes. Can be used with imgui module.\n```yaml\n# styles.yaml\n\"*\":\n color: black\n background_color: grey\n\n\"#error\":\n background_color: red\n```\n```python\n# cascading styles\nstylesheet = partial(get_styles, assets.styles)\nFoo = namedtuple(\"Foo\", [\"id\"])\nstyles = stylesheet(Foo(id=\"error\"))\nassert styles[\"background_color\"] == \"red\"\n\n# use with imgui\nwith imgui.render(gui, surface, stylesheet) as render:\n render(imgui.button(\"Click me!\"), center=(100, 100))\n```\n\n\n## [`make_sprite` function](pygskin/surface.py)\nCreate a sprite from an image.\n```python\nplayer = make_sprite(assets.player, center=player_pos)\n```\n\n\n## [`rotate_surface` function](pygskin/surface.py)\nRotate a surface in place or around a specified point.\n```python\nrotated_image = rotate_surface(image, angle, center=(0, 0))\n```\n\n\n## [`to_snakecase` function](pygskin/text.py)\nConvert CapWords to snake_case.\n\n\n## [`speech_duration` function](pygskin/text.py)\nCalculate rough speech duration in seconds.\n\n\n## [`tile` function](pygskin/tile.py)\nGenerate a blit sequence to tile an image across a surface.\n```python\nscreen.blits(tile(screen.get_rect(), assets.grass))\n```\n\n\n## [`angle_between` function](pygskin/vector.py)\nCalculate the angle between two points.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": null,
"version": "0.3.0",
"project_urls": {
"documentation": "https://github.com/andyhd/pygskin/blob/main/README.md",
"homepage": "https://github.com/andyhd/pygskin",
"issues": "https://github.com/andyhd/pygskin/issues",
"repository": "https://github.com/andyhd/pygskin"
},
"split_keywords": [
"framework",
" game",
" pygame"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d74c427bbcb061be35df2135b4ef5862e7745aca32caab66f86a90b7c128c614",
"md5": "90af315d2e3962058ba3fb4e251eaf25",
"sha256": "64dc2bd3cabbed89c2bb13e4293ee7a199a2a1784240a2e4b96b17294f546eaf"
},
"downloads": -1,
"filename": "pygskin-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "90af315d2e3962058ba3fb4e251eaf25",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 26886,
"upload_time": "2025-02-10T23:41:30",
"upload_time_iso_8601": "2025-02-10T23:41:30.297555Z",
"url": "https://files.pythonhosted.org/packages/d7/4c/427bbcb061be35df2135b4ef5862e7745aca32caab66f86a90b7c128c614/pygskin-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c2a6ae196469dd5c9f3606de7b90bdef9e79ebaa6912a48d695128abaf86d181",
"md5": "af0cdfdddd00b2f6cdbfc3d500c37ba3",
"sha256": "c45066b89bbc97f02e26df876cd8bed900d9a2c0a5899ea1b41eb8d3418e4182"
},
"downloads": -1,
"filename": "pygskin-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "af0cdfdddd00b2f6cdbfc3d500c37ba3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 29402,
"upload_time": "2025-02-10T23:41:32",
"upload_time_iso_8601": "2025-02-10T23:41:32.220544Z",
"url": "https://files.pythonhosted.org/packages/c2/a6/ae196469dd5c9f3606de7b90bdef9e79ebaa6912a48d695128abaf86d181/pygskin-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-02-10 23:41:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "andyhd",
"github_project": "pygskin",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "pygame-ce",
"specs": []
}
],
"lcname": "pygskin"
}