# 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), (0, 0))
```
## [`Assets` class](pygskin/assets.py)
Provides attribute access to asset files and batch loading
```python
assets = Assets()
screen.blit(assets.player, (0, 0))
assets.player_spawn_sfx.play()
```
## [`Timer` class](pygskin/timer.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` function.
## [`get_ecs_update_fn` function](pygskin/ecs.py)
An extremely simple ECS implementation.
```python
@filter_entities(has_velocity)
def apply_velocity(entity):
entity.pos += entity.velocity
ecs_update = get_ecs_update_fn([apply_velocity])
@dataclass
class Entity:
pos: Vector2
velocity: Vector2
ecs_update([Entity(pos=Vector2(0, 0), velocity=Vector2(1, 1)])
```
## [`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, (0, 0))
```
## [`rhash`/`unrhash` functions](pygskin/hash.py)
Simple reversible hash function for generating unique IDs.
```python
id = rhash("foo")
assert unrhash(id) == "foo"
```
## [`imgui` module](pygskin/imgui.py)
Immediate mode GUI.
```python
gui = imgui.IMGUI()
def main_loop(screen, events, quit):
with imgui.render(gui, screen) as render:
if render(imgui.button("Quit"), center=(100, 200)):
break
```
## [`lazy` class](pygskin/lazy.py)
Lazy loading object proxy.
```python
image = lazy(lambda: pygame.image.load("foo.png"))
screen.blit(image, (0, 0))
```
## [`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_title: [start_level, enter_level_code],
show_code_prompt: [start_level, return_to_titles],
play_level: [end_level],
show_game_over: [return_to_titles],
}
)
def show_main_menu(surface, events, exit):
surface.blit(assets.main_menu, (0, 0))
for event in events:
if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
exit("start_level")
if event.type == pygame.KEYDOWN and event.key == pygame.K_c:
exit("enter_code")
def start_level(input):
return play_level if input == "start_level" else None
def enter_level_code(input):
return show_code_prompt if input == "enter_code" else None
```
## [`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), (0, 0))
walk_frames = [get_sprite(0, i) for i in range(4)]
walk_anim = animate(walk_frames, timer.quotient)
```
## [`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` and `snakecase_to_capwords` functions](pygskin/text.py)
Convert between snake_case and CapWords.
## [`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/8a/9d/922be33de3387f42cecb499f55d383ccd67a03d7d1f0fd0101f28ad14048/pygskin-0.2.1.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), (0, 0))\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, (0, 0))\nassets.player_spawn_sfx.play()\n```\n\n\n## [`Timer` class](pygskin/timer.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` function.\n\n\n## [`get_ecs_update_fn` function](pygskin/ecs.py)\nAn extremely simple ECS implementation.\n```python\n@filter_entities(has_velocity)\ndef apply_velocity(entity):\n entity.pos += entity.velocity\n\necs_update = get_ecs_update_fn([apply_velocity])\n\n@dataclass\nclass Entity:\n pos: Vector2\n velocity: Vector2\n\necs_update([Entity(pos=Vector2(0, 0), velocity=Vector2(1, 1)])\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, (0, 0))\n```\n\n\n## [`rhash`/`unrhash` functions](pygskin/hash.py)\nSimple reversible hash function for generating unique IDs.\n```python\nid = rhash(\"foo\")\nassert unrhash(id) == \"foo\"\n```\n\n\n## [`imgui` module](pygskin/imgui.py)\nImmediate mode GUI.\n```python\ngui = imgui.IMGUI()\n\ndef main_loop(screen, events, quit):\n with imgui.render(gui, screen) as render:\n if render(imgui.button(\"Quit\"), center=(100, 200)):\n break\n```\n\n\n## [`lazy` class](pygskin/lazy.py)\nLazy loading object proxy.\n```python\nimage = lazy(lambda: pygame.image.load(\"foo.png\"))\nscreen.blit(image, (0, 0))\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 {\n show_title: [start_level, enter_level_code],\n show_code_prompt: [start_level, return_to_titles],\n play_level: [end_level],\n show_game_over: [return_to_titles],\n }\n )\n\ndef show_main_menu(surface, events, exit):\n surface.blit(assets.main_menu, (0, 0))\n for event in events:\n if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:\n exit(\"start_level\")\n if event.type == pygame.KEYDOWN and event.key == pygame.K_c:\n exit(\"enter_code\")\n\ndef start_level(input):\n return play_level if input == \"start_level\" else None\n\ndef enter_level_code(input):\n return show_code_prompt if input == \"enter_code\" else None\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), (0, 0))\nwalk_frames = [get_sprite(0, i) for i in range(4)]\nwalk_anim = animate(walk_frames, timer.quotient)\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` and `snakecase_to_capwords` functions](pygskin/text.py)\nConvert between snake_case and CapWords.\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.2.1",
"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": "",
"digests": {
"blake2b_256": "e9520ac393b37e64730bf27e0906c12fa4e3e52641c3d1c6506bad122826e1e5",
"md5": "71759134866a43d2bd4e48fa9f2ff0e1",
"sha256": "bdbfea6ec81385f56b2606c46c0ff2077e262480fb13397662dd9229e8484b3c"
},
"downloads": -1,
"filename": "pygskin-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "71759134866a43d2bd4e48fa9f2ff0e1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 23913,
"upload_time": "2025-01-16T00:28:16",
"upload_time_iso_8601": "2025-01-16T00:28:16.925442Z",
"url": "https://files.pythonhosted.org/packages/e9/52/0ac393b37e64730bf27e0906c12fa4e3e52641c3d1c6506bad122826e1e5/pygskin-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8a9d922be33de3387f42cecb499f55d383ccd67a03d7d1f0fd0101f28ad14048",
"md5": "7ef3f8ace473b13bd5ea9416525ed2fd",
"sha256": "8c6015f003e6abc81325fa9a663b3d2b7300aa36abf1509baf9091760b02598d"
},
"downloads": -1,
"filename": "pygskin-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "7ef3f8ace473b13bd5ea9416525ed2fd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 18504,
"upload_time": "2025-01-16T00:28:19",
"upload_time_iso_8601": "2025-01-16T00:28:19.675474Z",
"url": "https://files.pythonhosted.org/packages/8a/9d/922be33de3387f42cecb499f55d383ccd67a03d7d1f0fd0101f28ad14048/pygskin-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-16 00:28:19",
"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"
}