Skip to main content

pygameP

Pygame Plus — An advanced extension framework for Pygame, providing GLSL shader effects, performance optimization tools, JSON scene management, a simple physics engine, and extended input device support.

Installation

pip install pygameP

Dependencies are installed automatically:

  • pygame >= 2.0.0
  • PyOpenGL >= 3.1.0 (for shader support)

Features

Module Description
shaders GLSL shader system + built-in effects (grayscale, blur, invert, brightness, pulse, wave)
performance Object pool, spatial hash, FPS monitor, batch renderer
scene .pgstage JSON scene files with multi-scene switching
physics Simple rigid-body physics (gravity, collision, raycasting)
input Unified input for keyboard, mouse, gamepad, and multi-touch
async_utils Non-blocking async timer and loop runner for game loops
assets Global asset loader with caching (images, sounds, fonts, data)
save JSON-based save system and config manager
camera 2D camera with smooth follow, screen shake, zoom, and bounds
audio Audio manager with BGM fade, SFX pooling, and volume control
gui GUI widgets: Button, Slider, TextInput, ProgressBar, Label
debug Debug overlay with FPS, entity count, and hitbox rendering
tiled Tiled Map Editor (.tmx) importer for tile maps and objects

Quick Start

1. GLSL Shader Effects

Load shaders from .glsl files or inline code strings. Apply to the entire screen or individual sprites.

from pygameP import Shader, ShaderEffect, BuiltInEffects

# Use built-in effects
grayscale = BuiltInEffects.grayscale()
blur = BuiltInEffects.blur(radius=3.0)
invert = BuiltInEffects.invert()
pulse = BuiltInEffects.pulse(speed=2.0)
wave = BuiltInEffects.wave(amplitude=0.05, frequency=10.0)

# Apply to the entire screen
grayscale.apply(screen)

# Apply to a single sprite
pulse.apply(my_sprite)

# Custom GLSL code
my_shader = Shader(fragment_source="""
#version 330 core
in vec2 v_texcoord;
out vec4 frag_color;
uniform sampler2D u_texture;
uniform float u_time;
void main() {
    vec4 c = texture(u_texture, v_texcoord);
    frag_color = vec4(c.r, c.g * abs(sin(u_time)), c.b, c.a);
}
""")

# Load from file
custom = Shader(
    vertex_file="assets/shaders/default.vert",
    fragment_file="assets/shaders/plasma.frag"
)

2. Performance Optimization

from pygameP import ObjectPool, SpatialHash, FPSMonitor, BatchRenderer

# Object pool — reduce allocation overhead for bullets/particles
bullet_pool = ObjectPool(lambda: Bullet(), initial_size=200)
bullet = bullet_pool.acquire()   # grab from pool
# ... use it ...
bullet_pool.release(bullet)      # return to pool

# Spatial hash — fast collision detection
spatial = SpatialHash(cell_size=64)
spatial.insert(enemy, enemy.rect)
nearby = spatial.query(player.rect)  # only check nearby objects

# FPS monitor + adaptive quality
fps_monitor = FPSMonitor(target_fps=60)
while running:
    dt = fps_monitor.tick()
    if fps_monitor.should_reduce_quality():
        reduce_particle_count()

# Batch rendering — merge draw calls
batch = BatchRenderer(screen)
for sprite in sprites:
    batch.blit(sprite.image, sprite.rect.topleft)
batch.render()  # execute all at once

3. Scene Management (.pgstage)

.pgstage is pygameP's custom scene file format, based on JSON.

Scene Editor: .pgstage files are created and managed by pgstage Editor, a visual scene editor. The pygameP library only loads and runs scenes. Online Editor: https://tomlct2015.github.io/pygameP/editor/pgstage-editor

{
  "name": "ExampleLevel",
  "width": 1600,
  "height": 1200,
  "background_color": [20, 25, 40],
  "camera_x": 0,
  "camera_y": 0,
  "properties": {
    "music": "assets/music/level1.ogg",
    "difficulty": "normal"
  },
  "entities": [
    {
      "type": "Player",
      "x": 100,
      "y": 800,
      "layer": 5,
      "hp": 100,
      "tag": "player"
    },
    {
      "type": "Enemy",
      "x": 500,
      "y": 800,
      "layer": 4,
      "hp": 50,
      "ai": "patrol"
    }
  ]
}

Usage in Python:

from pygameP import Scene, SceneManager, SceneEntity

# Load a scene from .pgstage file
scene = Scene.load("levels/level1.pgstage")

# Multi-scene management (with transition)
manager = SceneManager()
manager.load("menu", "scenes/menu.pgstage")
manager.load("game", "levels/level1.pgstage")
manager.switch_to("game", transition=0.5)

# Game loop
while running:
    dt = clock.tick(60) / 1000.0
    manager.update(dt)
    manager.draw(screen)

4. Simple Physics Engine

from pygameP import RigidBody, PhysicsWorld, BoxCollider, CircleCollider

# Create physics world
world = PhysicsWorld(gravity=980.0)

# Dynamic rigid body (affected by gravity)
player = RigidBody(x=100, y=0, mass=1.0, collider=BoxCollider(32, 64))
player.restitution = 0.3  # bounciness
player.friction = 0.2     # friction
world.add_body(player)

# Static rigid body (ground, platforms)
ground = RigidBody(x=0, y=600, mass=0, collider=BoxCollider(800, 40))
world.add_body(ground)

# Apply force or impulse
player.apply_force(500, 0)        # continuous force
player.apply_impulse(0, -300)     # jump (instant)

# Update each frame
world.update(dt)

# Collision callback
def on_hit(body1, body2):
    print("Collision!")
world.on_collision = on_hit

# Raycasting
hit = world.raycast((100, 300), (1, 0), max_distance=500)
if hit:
    body, distance, point = hit
    print(f"Hit {body} at distance {distance}")

5. Extended Input Devices

from pygameP import InputManager

input_mgr = InputManager()

# Map actions to multiple input sources
input_mgr.map_action("jump", "keyboard", pygame.K_SPACE)
input_mgr.map_action("jump", "gamepad", (0, 0))  # gamepad 0, button 0

input_mgr.map_action("shoot", "mouse", 1)  # left mouse button
input_mgr.map_action("move_right", "gamepad", (0, "axis_0"))

# Game loop
while running:
    events = pygame.event.get()
    input_mgr.update(events)

    if input_mgr.is_action_just_pressed("jump"):
        player.jump()
    if input_mgr.is_action_pressed("move_right"):
        player.move_right()

    # Analog input (gamepad stick)
    move_x = input_mgr.get_action_value("move_right")

    # Direct gamepad access
    pad = input_mgr.get_gamepad(0)
    if pad:
        left_stick = pad.get_left_stick()
        pad.rumble(0.5, 0.5, 100)  # vibration

    # Touch input
    if input_mgr.touch.is_touching():
        pos = input_mgr.touch.get_touch_position()

Supported input devices:

  • Keyboard — key press/release/just-pressed
  • Mouse — position, relative motion, scroll wheel, button state
  • Gamepad — buttons, stick axes, D-pad, rumble/vibration
  • Touch — multi-touch, touch start/end/move

6. Async Timer & Loop Runner

Non-blocking scheduled tasks for game loops.

from pygameP import AsyncTimer, LoopRunner

timer = AsyncTimer()

# Infinite loop — run callback every N seconds
timer.loop(0.1, update_ai)

# One-shot — run once after delay
timer.after(3.0, spawn_boss)

# Repeating — run every N seconds (stoppable)
task = timer.every(1.0, save_checkpoint)
task.stop()  # cancel later

# Per-frame loop runner
runner = LoopRunner()
runner.add("physics", update_physics)
runner.add("ai", update_ai)

# In game loop:
timer.update(dt)
runner.update(dt)

7. Asset Manager

Global resource loader with automatic caching.

from pygameP import AssetManager

assets = AssetManager("assets")

# Load (cached after first load)
img = assets.image("sprites/player.png")
snd = assets.sound("sfx/jump.ogg")
fnt = assets.font("fonts/arial.ttf", 24)
data = assets.json("data/level1.json")

# Preload all at startup
assets.preload_images(["bg.png", "player.png", "enemy.png"])
assets.preload_sounds(["jump.ogg", "hit.ogg"])

# Background music
assets.music("music/theme.ogg", fade_ms=1000)
assets.stop_music(fade_ms=500)

# Stats
print(assets.stats())  # {'images': 3, 'sounds': 2, ...}

# Cleanup
assets.unload("sprites/player.png")
assets.clear()  # clear all caches

8. Save System & Config

JSON-based save slots and game configuration.

from pygameP import SaveManager, Config

# Save game
save = SaveManager("saves")
save.save("slot1", {"level": 5, "hp": 100, "items": ["sword", "shield"]})
data = save.load("slot1")
save.exists("slot1")  # True
save.list_slots()     # ["slot1"]
save.delete("slot1")

# Config with defaults
cfg = Config("settings.json", defaults={
    "volume": 0.8,
    "resolution": [1280, 720],
    "fullscreen": False,
})
vol = cfg.get("volume")      # 0.8
cfg.set("volume", 0.5)
cfg["fullscreen"] = True     # bracket access
cfg.save()                   # write to disk
cfg.reset()                  # reset to defaults

9. Camera System

2D camera with smooth follow, screen shake, zoom, and world bounds.

from pygameP import Camera

cam = Camera(1280, 720, world_width=3200, world_height=1800)

# Smooth follow player
cam.follow(player.x, player.y, speed=5.0, dead_zone=20)

# Instant snap to position
cam.look_at(500, 300)

# Screen shake on hit
cam.shake(intensity=8, duration=0.3)

# Zoom
cam.zoom_to(1.5, speed=3.0)

# In game loop:
cam.update(dt)
offset = cam.offset  # (dx, dy) to subtract from entity positions

# Coordinate conversion
sx, sy = cam.world_to_screen(world_x, world_y)
wx, wy = cam.screen_to_world(mouse_x, mouse_y)

# Visibility check
if cam.visible(entity.x, entity.y, 32, 32):
    entity.draw(screen)

10. Audio Manager

BGM fade, SFX pooling, and volume control.

from pygameP import AudioManager

audio = AudioManager(sfx_channels=16)

# Background music with fade
audio.play_bgm("music/theme.ogg", fade_ms=1000)
audio.set_bgm_volume(0.7)
audio.stop_bgm(fade_ms=500)
audio.pause_bgm()
audio.resume_bgm()

# Sound effects (auto-cached)
audio.play_sfx("sfx/jump.ogg")
audio.play_sfx("sfx/explosion.ogg", volume=0.5)

# Volume groups
audio.set_master_volume(0.8)  # affects everything
audio.set_sfx_volume(0.6)     # affects SFX only

# Preload
audio.preload_sfx(["jump.ogg", "hit.ogg", "coin.ogg"])

11. GUI Widgets

Button, Slider, TextInput, ProgressBar, Label.

from pygameP import Button, Slider, TextInput, ProgressBar, Label

btn = Button(100, 200, 200, 50, "Start Game", callback=start_game)
slider = Slider(100, 300, 200, min_val=0.0, max_val=1.0, value=0.8)
text = TextInput(100, 400, 200, 40, placeholder="Enter name...")
bar = ProgressBar(100, 500, 200, 20, value=0.75)
label = Label(100, 550, "Score: 0", font_size=24)

# In game loop:
for event in pygame.event.get():
    btn.handle_event(event)
    slider.handle_event(event)
    text.handle_event(event)

text.update(dt)  # cursor blink

btn.draw(screen)
slider.draw(screen)
text.draw(screen)
bar.draw(screen)
label.draw(screen)

# Access values
print(slider.value)   # 0.0 to 1.0
print(text.text)      # typed string
bar.value = 0.9       # auto-clamped to 0.0-1.0

12. Debug Overlay

Press F1 to toggle. Shows FPS, entity count, hitboxes, and custom stats.

from pygameP import DebugOverlay

dbg = DebugOverlay()
dbg.show_hitboxes = True
dbg.show_fps = True
dbg.show_entity_count = True
dbg.hotkey = pygame.K_F1  # configurable

# In game loop:
dbg.handle_event(event)
dbg.update(dt, entity_count=len(entities), score=score, ammo=ammo)
dbg.draw(screen, entities)  # draws hitboxes + overlay

# Custom stats
dbg.set_stat("health", player.hp)
dbg.set_stat("mode", "survival")

13. Tiled Map Import

Load Tiled Map Editor (.tmx) files.

from pygameP import TiledLoader

loader = TiledLoader()
tilemap = loader.load("levels/level1.tmx")

# Access layers
for layer in tilemap.layers:
    print(layer.name, layer.width, layer.height)

# Get tile at position
tile_id = tilemap.get_tile("Ground", x=5, y=3)

# Access objects
for obj in tilemap.objects:
    print(obj.name, obj.type, obj.x, obj.y)

# Find objects by type
enemies = tilemap.get_object_layer("Enemies").get_objects_by_type("Enemy")
spawn = tilemap.get_object_layer("Spawns").get_object_by_name("PlayerStart")

# Tileset info
for ts in tilemap.tilesets:
    print(ts.name, ts.first_gid, ts.image_source)

# Coordinate conversion
px, py = tilemap.tile_to_pixel(5, 3)
tx, ty = tilemap.pixel_to_pixel(mouse_x, mouse_y)

# Check visibility
if tilemap.visible(entity.rect):
    entity.draw(screen)

API Reference

Shader

  • Shader(vertex_source, fragment_source, vertex_file, fragment_file) — create shader
  • shader.use() / shader.stop() — enable/disable
  • shader.set_uniform(name, value) — set uniform (float, int, vec2, vec3, vec4)
  • shader.apply_to_surface(surface) — apply to entire screen
  • shader.apply_to_sprite(sprite) — apply to single sprite

BuiltInEffects

  • grayscale() — grayscale filter
  • blur(radius) — blur effect
  • invert() — color inversion
  • brightness(amount) — brightness adjustment
  • pulse(speed) — pulsing glow
  • wave(amplitude, frequency) — wave distortion

ObjectPool

  • acquire() — get object from pool
  • release(obj) — return object
  • release_all() — return all objects
  • resize(n) — adjust pool size

SpatialHash

  • insert(obj, rect) — insert object
  • query(rect) — query objects in area
  • query_nearby(obj, rect) — query nearby (excludes self)
  • remove(obj) / clear()

Scene / SceneManager

  • Scene.load(path) — load .pgstage file
  • SceneManager.load(name, path) — load and register scene
  • SceneManager.switch_to(name, transition) — switch scenes

PhysicsWorld

  • add_body(body) / remove_body(body)
  • update(dt) — step physics (handles gravity and collisions)
  • raycast(start, direction, max_distance) — ray cast query

InputManager

  • update(events) — update all input devices
  • is_action_pressed(action) — is action held down
  • is_action_just_pressed(action) — was action just pressed this frame
  • get_action_value(action) — get analog value (-1 to 1)
  • map_action(action, device, binding) — map action to input

AsyncTimer

  • loop(interval, callback) — run callback every N seconds (infinite)
  • every(interval, callback) — alias for loop()
  • after(delay, callback) — run once after delay
  • update(dt) — advance all tasks
  • cancel_all() — cancel all tasks

LoopRunner

  • add(name, callback) — register per-frame callback
  • remove(name) — remove callback
  • update(dt) — call all callbacks with dt

AssetManager

  • image(path) — load/cache image
  • sound(path) — load/cache sound
  • font(path, size) — load/cache font
  • json(path) — load/cache JSON data
  • music(path, fade_ms) — play BGM
  • preload_images(paths) — bulk preload
  • stats() — cache statistics
  • clear() — clear all caches

SaveManager

  • save(slot, data) — save to slot
  • load(slot) — load from slot
  • exists(slot) — check if slot exists
  • delete(slot) — delete slot
  • list_slots() — list all slots

Config

  • get(key, default) — get value with fallback
  • set(key, value) — set value
  • save() — write to disk
  • reset() — reset to defaults
  • config[key] — bracket access

Camera

  • follow(x, y, speed, dead_zone) — smooth follow
  • look_at(x, y) — instant snap
  • shake(intensity, duration) — screen shake
  • zoom_to(value, speed) — smooth zoom
  • update(dt) — update camera
  • offset — (dx, dy) for rendering
  • world_to_screen(x, y) — coordinate conversion
  • screen_to_world(x, y) — reverse conversion
  • visible(rect) — visibility check

AudioManager

  • play_bgm(path, fade_ms) — play background music
  • stop_bgm(fade_ms) — stop BGM with fade
  • play_sfx(path, volume) — play sound effect
  • set_master_volume(v) — global volume
  • set_bgm_volume(v) — BGM volume
  • set_sfx_volume(v) — SFX volume
  • preload_sfx(paths) — bulk preload

GUI Widgets

  • Button(x, y, w, h, text, callback) — clickable button
  • Slider(x, y, w, min, max, value) — horizontal slider
  • TextInput(x, y, w, h, placeholder) — text input field
  • ProgressBar(x, y, w, h, value) — progress bar
  • Label(x, y, text, font_size) — static text
  • All widgets: handle_event(event), update(dt), draw(surface)

DebugOverlay

  • handle_event(event) — toggle on F1
  • update(dt, entity_count, **custom) — update stats
  • draw(surface, entities) — render overlay + hitboxes
  • set_stat(key, value) — add custom stat

TiledLoader

  • load(path) — load .tmx file
  • Returns TileMap with:
    • layers — list of TileLayer
    • object_layers — list of ObjectLayer
    • tilesets — list of Tileset
    • get_tile(layer_name, x, y) — get tile ID
    • tile_to_pixel(tx, ty) — coordinate conversion

Full Example

import pygame
from pygameP import (
    SceneManager, Scene, SceneEntity,
    PhysicsWorld, RigidBody, BoxCollider,
    InputManager, FPSMonitor, BuiltInEffects
)

pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

# Scene
manager = SceneManager()
game = Scene({"name": "Game", "width": 800, "height": 600,
              "background_color": [30, 40, 60]})
manager.add("game", game)
manager.switch_to("game")

# Physics
world = PhysicsWorld(gravity=980.0)
player = RigidBody(400, 100, mass=1.0, collider=BoxCollider(32, 32))
world.add_body(player)
ground = RigidBody(0, 550, mass=0, collider=BoxCollider(800, 50))
world.add_body(ground)

# Input
input_mgr = InputManager()
input_mgr.map_action("jump", "keyboard", pygame.K_SPACE)
input_mgr.map_action("left", "keyboard", pygame.K_LEFT)
input_mgr.map_action("right", "keyboard", pygame.K_RIGHT)

# FPS monitor
fps = FPSMonitor(target_fps=60)

# Shader effect
effect = BuiltInEffects.pulse(speed=2.0)

running = True
while running:
    dt = clock.tick(60) / 1000.0
    fps.tick()

    events = pygame.event.get()
    input_mgr.update(events)

    for event in events:
        if event.type == pygame.QUIT:
            running = False

    # Input
    if input_mgr.is_action_just_pressed("jump") and player.grounded:
        player.apply_impulse(0, -500)
    if input_mgr.is_action_pressed("left"):
        player.apply_force(-300, 0)
    if input_mgr.is_action_pressed("right"):
        player.apply_force(300, 0)

    # Update
    world.update(dt)
    manager.update(dt)

    # Draw
    manager.draw(screen)
    pygame.draw.rect(screen, (255, 200, 100),
                     (player.x, player.y, 32, 32))
    pygame.draw.rect(screen, (100, 100, 100),
                     (ground.x, ground.y, 800, 50))

    pygame.display.flip()

pygame.quit()

License

MIT License

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygamep-0.0.9.tar.gz (109.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygamep-0.0.9-py3-none-any.whl (93.0 kB view details)

Uploaded Python 3

File details

Details for the file pygamep-0.0.9.tar.gz.

File metadata

  • Download URL: pygamep-0.0.9.tar.gz
  • Upload date:
  • Size: 109.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.8

File hashes

Hashes for pygamep-0.0.9.tar.gz
Algorithm Hash digest
SHA256 613d33d9ba4d962e72a3c4ad12a9935c28722df61ea1cd6ba73c5db6b0080121
MD5 d4b4699cb2b4f006e86469b0da043f57
BLAKE2b-256 87306ee835fc0a61b9b53842f720f3e39a26eb7466d12650f589b5f766f4faef

See more details on using hashes here.

File details

Details for the file pygamep-0.0.9-py3-none-any.whl.

File metadata

  • Download URL: pygamep-0.0.9-py3-none-any.whl
  • Upload date:
  • Size: 93.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.8

File hashes

Hashes for pygamep-0.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 135d25344ef5967d797d1c614186e6622534c61716958a420b594bf463de5c3c
MD5 028c8d1c94002b81dc7b080c1cd4a174
BLAKE2b-256 5ead0f6ae044d5b3a88cd93428daa079003cc05d5b57fd47a063deeece09a6dd

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.10

2 files

This release

0.0.9 This release

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page