Skip to main content

Pygame Visor - a simple Camera/Viewport library

Project description

Pygame Visor

Camera/Viewport library.

Currently only works with pygame-ce, as it's using pygame.FRect in some parts.

License

MIT © 2025 Sani (https://github.com/nitori)

Install

Currently pygame-ce is required instead of pygame. If you have pygame installed, uninstall it first.

pip install pygame-visor pygame-ce

or using uv

uv add pygame-visor pygame-ce

Camera/Viewport System – Feature Overview

  • Translate between world and screen coordinates (world_to_screen, screen_to_world)
    • Needed for input mapping (e.g. screen_to_world(surface_rect, mouse_pos))
  • Support multiple view modes:
    • Fixed world area (scales with screen), with or without padding
    • Fixed zoom level (screen res affects visible area)
  • Camera movement via external control (move_to(pos))
  • Optional clamping to world bounds / limits (camera can't move past edges)
  • Multiple views supported via independent instances (multi-camera/minimap/splitscreen)
  • Support lerping/smooth movement to a target position (or perhaps have the user do it themselves?)
    • Can probably get some more love, but a basic lerp already works.
  • Expose get_bounding_box(surface_rect) for rendering logic
    • Camera "requests" world region using the bounding box method above; game provides matching surfaces
    • Accept surface size/rect for bounding box calculations (for the different view modes above)
  • Handle zooming, including fractional zoom
    • UX: Optional zoom-to-cursor behavior (maintains world point under cursor)

Optional stuff for now

  • debug helpers (draw bounding box, show mouse world pos, etc.)
  • Overscan/margin support for effects, camera shake, etc.

View/Visor Modes

1. Fixed Region (letterbox)

  • A specific world size (e.g. 400x300 units) is always shown.
  • If the screen's aspect ratio differs, black bars (letterboxing) fill the space.
  • Scaling happens to fit the screen, preserving aspect ratio.

2. Fixed Region (extended view)

  • A specific world size (e.g. 400x300) is the minimum shown.
  • If the screen is larger/wider, more of the world is revealed (i.e. expands the visible region).
  • No letterboxing; fills the screen with as much world as possible.

Basic Usage

# get a surface the view can draw on. Could also be screen directly.
surf = pygame.Surface(400, 300)

# Create a Visor instance
visor = Visor(
    VisorMode.RegionLetterbox,  # One of two modes (see above)
    screen.get_rect(),  # pass in the rect of the surface you wish to draw on.
    region=(0, 0, 400, 300),  # world region to "view"
    limits=[-2000, -2000, 2000, 2000],  # Optional min/max x,y coords to constrain the visor to.
)

while True:
    # ...

    # Get the world bounding box (it returns a pygame.FRect, indicating the area of
    # the world that is currently visible)
    # Uses the stored screen rect passed in the constructor.
    # Use update_screen(new_rect) if your screen/surface got resized.
    bbox = visor.get_bounding_box()

    # Get iterable of surfaces, that cover the bounding box
    # This you need to implement yourself!
    # Return an iterable of tuples: ((world_x, world_y), tile_surface)
    # Where tile_surface (at the moment) must have world coords width/height. Surfaces are expected to be
    # pre-rendered at world-scale (1 unit = 1 pixel in world space). The Visor system will scale them
    # appropriately based on screen resolution and visor mode.
    tiles = world.get_tiles_iterable(bbox)

    # render tiles to surface, the visor will autoscale them to the correct size.
    visor.render(surf, tiles)

    # optional (if you don't use the screen directly), blit to screen:
    screen.blit(surf, (0, 0))

    # ...

If you have a player, that needs to be rendered on top of the map. Assuming player.surf holds your players surface, and player.rect holds the players position:

while True:
    # ...

    # update visor based on player position *before* getting the bbox
    visor.move_to(player.rect.center)  # visor.lerp_to(...) is also possible
    bbox = visor.get_bounding_box()

    # ... get tiles etc.

    # render map
    visor.render(surf, tiles)

    # render the player using visor.render, so it will be scaled correctly
    visor.render(surf, [
        (player.rect.topleft, player.surf)
    ])

    # ...

Examples

See example_map.py for a full working example of a main visor and a minimap using two independent cameras.

example_map.png


See example_modes.py to demonstrate the difference between VisorMode.RegionLetterbox and VisorMode.RegionExpand.

example_modes.png


See example_zoom.py to demonstrate a simple way to zoom your visor in and out.

example_zoom.png


See example_mouse.py for a demonstration of tracking mouse screen pos to world tile position.

example_mouse.png


See example_ui.py for a simple UI example, of how to position them in the "active" area, in any VisorMode.

example_ui.png


See example_split_screen.py for a simple split screen example with two player. Using WASD and Arrow keys for independent movement.

example_split_screen.png


See example_shake.py for a simple shaking camera example.

See example_static_camera.py for a static camera fixed to regions. The camera does not follow the player all the time, only when the player moves to a new region.


See example_parallax.py for a simple example of a "background view" that moves "slower" than the foreground. A traditional parallax effect.

For fun, I also added a variant that uses _sdl2 Textures: See example_parallax_sdl2.py.

example_parallax.png

Project details


Download files

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

Source Distribution

pygame_visor-0.4.2.tar.gz (7.7 kB view details)

Uploaded Source

Built Distribution

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

pygame_visor-0.4.2-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file pygame_visor-0.4.2.tar.gz.

File metadata

  • Download URL: pygame_visor-0.4.2.tar.gz
  • Upload date:
  • Size: 7.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pygame_visor-0.4.2.tar.gz
Algorithm Hash digest
SHA256 17efca5882ca956f80e8b447429b632e43eb3af77527dcb843a5e4a0db387d26
MD5 b81b0b744b833c8196e9124339bd24ea
BLAKE2b-256 81a1278589793277fd62ca28dfc12ca203e31af6b4b842e790c389718d306aa4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygame_visor-0.4.2.tar.gz:

Publisher: push-to-pypi.yaml on nitori/pygame-visor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pygame_visor-0.4.2-py3-none-any.whl.

File metadata

  • Download URL: pygame_visor-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pygame_visor-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c8a69cc6692eff9c206c526ffd2c91b29b3dba57595784450cf3680ba3280a09
MD5 43fe51ccfcf9f219996caae844efe9db
BLAKE2b-256 9c6a335964e276c6bd321257c8608f0718133a2eb26bb3654071e6a8c3ab7fb4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygame_visor-0.4.2-py3-none-any.whl:

Publisher: push-to-pypi.yaml on nitori/pygame-visor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page