Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/publish-documentation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: documentation

on:
push:
branches:
- main

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-python@v4
with:
python-version: 3.13

- run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pdoc

- run: |
pdoc pygskin --output-dir docs

- uses: actions/upload-artifact@v3
with:
path: docs

deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
73 changes: 73 additions & 0 deletions examples/quickstart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import pygame as pg
import pygskin

ground_y = 400

# Define a player entity with components
class Player(pygskin.Entity):
rect: pg.Rect = lambda: pg.Rect(0, 0, 32, 32).move_to(x=100, bottom=ground_y)
velocity: pg.Vector2 = pg.Vector2

# Create a player instance
player = Player()

# Create systems to handle player movement and physics
@pygskin.system
def handle_movement(rect: pg.Rect, velocity: pg.Vector2, *, events):
for event in events:
# Start moving left or right
if event.type == pg.KEYDOWN and event.key == pg.K_LEFT:
velocity.x = -5
if event.type == pg.KEYDOWN and event.key == pg.K_RIGHT:
velocity.x = 5

# Stop moving if the key is released
if event.type == pg.KEYUP and (
(event.key == pg.K_LEFT and velocity.x < 0)
or (event.key == pg.K_RIGHT and velocity.x > 0)
):
velocity.x = 0

rect.x += velocity.x

@pygskin.system
def handle_jump(rect: pg.Rect, velocity: pg.Vector2, *, events):
# Jump if the player is on the ground
if (
rect.bottom == ground_y
and any(ev.type == pg.KEYDOWN and ev.key == pg.K_SPACE for ev in events)
):
velocity.y = -15

@pygskin.system
def apply_physics(rect: pg.Rect, velocity: pg.Vector2):
# Apply gravity
velocity.y += 0.8

# Update position
rect.y += velocity.y

# Simple ground collision
if rect.bottom > ground_y:
rect.bottom = ground_y
velocity.y = 0

def game_loop(screen, events, quit_game):
# Quit the game if the escape key is pressed
if any(event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE for event in events):
quit_game()

handle_movement(events=events)
handle_jump(events=events)
apply_physics()

# Clear the screen
screen.fill("gray70")
# Draw ground
pg.draw.rect(screen, "gray30", pg.Rect(0, 400, 800, 200))
# Draw player
pg.draw.rect(screen, "red", player.rect)

# Create the game window and start the game
window = pg.Window(size=(800, 600), title="Pygskin Platformer Demo")
pygskin.run_game(window, game_loop)
191 changes: 191 additions & 0 deletions pygskin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,194 @@
"""
A lightweight, modern game development library built on top of Pygame.

## Overview

Pygskin provides a collection of tools and utilities to make game development
with Pygame more enjoyable and productive. It offers a clean, intuitive API
while maintaining the flexibility and simplicity of Pygame.

## Requirements

- Python 3.13 or higher
- [Pygame CE](https://pyga.me) 2.5.2

## Quick Start

Let's create a simple platformer game to get started with Pygskin! We'll build a
game where you can control a character that can move left, right, and jump. This
tutorial will walk you through some of the basic concepts of Pygskin while
creating something fun.

First, let's set up our imports. We'll use Pygame (imported as 'pg' for brevity)
and Pygskin:

```python
import pygame as pg
import pygskin
```

For our simple platformer, we'll need a ground for our character to walk on.
We'll position it 400 pixels from the top of the screen, which gives us plenty
of room for jumping:

```python
ground_y = 400
```

Now, let's create our player character! In Pygskin, we use an Entity Component
System (ECS) to organize our game objects. This might sound complex, but it's
actually quite simple - think of an Entity as a game object (like our player)
and components as the properties that define what that object can do.

For our player, we'll create a class that inherits from `pygskin.Entity`. We'll
give it two components:
- A `rect` component that defines where the player is on screen (we'll start
with a 32x32 pixel square)
- A `velocity` component that will help us handle movement

The `rect` component uses a lambda function to create a rectangle positioned at
x=100 and sitting on our ground. The `velocity` component is a simple Vector2
that will store our movement speed:

```python
class Player(pygskin.Entity):
rect: pg.Rect = lambda: pg.Rect(0, 0, 32, 32).move_to(x=100, bottom=ground_y)
velocity: pg.Vector2 = pg.Vector2

# Create a player instance
player = Player()
```

Next, we'll create a system to handle player movement. In Pygskin, systems are
functions that define how entities behave. We'll create a system that responds
to keyboard input to move our player left and right. The `@system` decorator
tells Pygskin to automatically call this function for any entity that has a
velocity component.

The `events` parameter (marked with `*` to make it keyword-only) will receive
all the input events from Pygame. We'll use these to detect when the player
presses the left or right arrow keys:

```python
@system
def handle_movement(rect: pg.Rect, velocity: pg.Vector2, *, events):
for event in events:
# Start moving left or right
if event.type == pg.KEYDOWN and event.key == pg.K_LEFT:
velocity.x = -5
if event.type == pg.KEYDOWN and event.key == pg.K_RIGHT:
velocity.x = 5

# Stop moving if the key is released
if event.type == pg.KEYUP and (
(event.key == pg.K_LEFT and velocity.x < 0)
or (event.key == pg.K_RIGHT and velocity.x > 0)
):
velocity.x = 0

rect.x += velocity.x
```

Now we need a game loop to tie everything together. The game loop is the heart
of our game - it runs every frame and handles:
- Processing input
- Updating game state
- Drawing everything to the screen

Our game loop receives three important parameters:
- `screen`: The Pygame surface we draw to
- `events`: The list of input events since the last frame
- `quit_game`: A function to safely exit the game

```python
def game_loop(screen, events, quit_game):
# Quit the game if the escape key is pressed
if any(event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE for event in events):
quit_game()

handle_movement(events=events)

# Clear the screen with a light gray background
screen.fill("gray70")
# Draw our ground as a dark gray rectangle
pg.draw.rect(screen, "gray30", pg.Rect(0, 400, 800, 200))
# Draw our player as a red square
pg.draw.rect(screen, "red", player.rect)
```

Finally, we create our game window and start the game! We'll make an 800x600
pixel window with a title:

```python
window = pg.Window(size=(800, 600), title="Pygskin Platformer Demo")
pygskin.run_game(window, game_loop)
```

At this point, you can run the game and move the red square left and right with
the arrow keys! But let's make it more interesting by adding a new system to
handle jumping. When the player presses the space bar and is on the ground,
we'll make them jump by giving them an upward velocity:

```python
@pygskin.system
def handle_jump(rect: pg.Rect, velocity: pg.Vector2, *, events):
# Jump if the player is on the ground
if (
rect.bottom == ground_y
and any(ev.type == pg.KEYDOWN and ev.key == pg.K_SPACE for ev in events)
):
velocity.y = -15
```

We need to handle gravity and movement too! Let's create a physics system that:
- Applies gravity to pull the player down
- Updates the player's position based on their velocity
- Stops the player when they hit the ground

```python
@pygskin.system
def apply_physics(rect: pg.Rect, velocity: pg.Vector2):
# Apply gravity
velocity.y += 0.8

# Update position
rect.y += velocity.y

# Simple ground collision
if rect.bottom > ground_y:
rect.bottom = ground_y
velocity.y = 0
```

Finally, we update our game loop to include our new systems:

```python
def game_loop(screen, events, quit_game):
# Quit the game if the escape key is pressed
if any(event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE for event in events):
quit_game()

handle_movement(events=events)
handle_jump(events=events)
apply_physics()

# Clear the screen
screen.fill("gray70")
# Draw ground
pg.draw.rect(screen, "gray30", pg.Rect(0, 400, 800, 200))
# Draw player
pg.draw.rect(screen, "red", player.rect)
```

Now you have a fully functional platformer! You can:
- Move left and right with the arrow keys
- Jump with the space bar
- Quit the game with the escape key

Try running the game and experiment with the values (like jump height, movement
speed, and gravity) to see how they affect the gameplay!
"""

from pygskin import easing
from pygskin import imgui
from pygskin.animation import EasingFn
Expand Down
Loading