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.0PyOpenGL >= 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:
.pgstagefiles 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/pdstage-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 shadershader.use()/shader.stop()— enable/disableshader.set_uniform(name, value)— set uniform (float, int, vec2, vec3, vec4)shader.apply_to_surface(surface)— apply to entire screenshader.apply_to_sprite(sprite)— apply to single sprite
BuiltInEffects
grayscale()— grayscale filterblur(radius)— blur effectinvert()— color inversionbrightness(amount)— brightness adjustmentpulse(speed)— pulsing glowwave(amplitude, frequency)— wave distortion
ObjectPool
acquire()— get object from poolrelease(obj)— return objectrelease_all()— return all objectsresize(n)— adjust pool size
SpatialHash
insert(obj, rect)— insert objectquery(rect)— query objects in areaquery_nearby(obj, rect)— query nearby (excludes self)remove(obj)/clear()
Scene / SceneManager
Scene.load(path)— load.pgstagefileSceneManager.load(name, path)— load and register sceneSceneManager.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 devicesis_action_pressed(action)— is action held downis_action_just_pressed(action)— was action just pressed this frameget_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 delayupdate(dt)— advance all taskscancel_all()— cancel all tasks
LoopRunner
add(name, callback)— register per-frame callbackremove(name)— remove callbackupdate(dt)— call all callbacks with dt
AssetManager
image(path)— load/cache imagesound(path)— load/cache soundfont(path, size)— load/cache fontjson(path)— load/cache JSON datamusic(path, fade_ms)— play BGMpreload_images(paths)— bulk preloadstats()— cache statisticsclear()— clear all caches
SaveManager
save(slot, data)— save to slotload(slot)— load from slotexists(slot)— check if slot existsdelete(slot)— delete slotlist_slots()— list all slots
Config
get(key, default)— get value with fallbackset(key, value)— set valuesave()— write to diskreset()— reset to defaultsconfig[key]— bracket access
Camera
follow(x, y, speed, dead_zone)— smooth followlook_at(x, y)— instant snapshake(intensity, duration)— screen shakezoom_to(value, speed)— smooth zoomupdate(dt)— update cameraoffset— (dx, dy) for renderingworld_to_screen(x, y)— coordinate conversionscreen_to_world(x, y)— reverse conversionvisible(rect)— visibility check
AudioManager
play_bgm(path, fade_ms)— play background musicstop_bgm(fade_ms)— stop BGM with fadeplay_sfx(path, volume)— play sound effectset_master_volume(v)— global volumeset_bgm_volume(v)— BGM volumeset_sfx_volume(v)— SFX volumepreload_sfx(paths)— bulk preload
GUI Widgets
Button(x, y, w, h, text, callback)— clickable buttonSlider(x, y, w, min, max, value)— horizontal sliderTextInput(x, y, w, h, placeholder)— text input fieldProgressBar(x, y, w, h, value)— progress barLabel(x, y, text, font_size)— static text- All widgets:
handle_event(event),update(dt),draw(surface)
DebugOverlay
handle_event(event)— toggle on F1update(dt, entity_count, **custom)— update statsdraw(surface, entities)— render overlay + hitboxesset_stat(key, value)— add custom stat
TiledLoader
load(path)— load .tmx file- Returns
TileMapwith:layers— list ofTileLayerobject_layers— list ofObjectLayertilesets— list ofTilesetget_tile(layer_name, x, y)— get tile IDtile_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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pygamep-0.0.4.tar.gz.
File metadata
- Download URL: pygamep-0.0.4.tar.gz
- Upload date:
- Size: 63.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a8e949cf4941b7aa072aaecf538e9c2b466f26eb4682678519bdeb2286d1375
|
|
| MD5 |
00085b17caa2e31ee54c26201a6d48cb
|
|
| BLAKE2b-256 |
ec24b1e29a72220508614b8d7a544619bd8943f0a1d84d56a5121da4a3d2d3d2
|
File details
Details for the file pygamep-0.0.4-py3-none-any.whl.
File metadata
- Download URL: pygamep-0.0.4-py3-none-any.whl
- Upload date:
- Size: 46.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d00966315d8e02cfb67715c2dbf19bc0beea23be810cf5bdb9e0d2b4e19433a7
|
|
| MD5 |
fa5e89fe0dd71b58bc8fbd747269a841
|
|
| BLAKE2b-256 |
02beda426d93121bf9195385f40e74d083b359f411bb120c4fce66bf12e3be48
|