Camera and camera behaviors¶
The camera in Sappho allows you to have a small viewport onto the current map and optionally scale it up to a larger resolution. This is useful, for example, when you have a map with 10x10 pixel tiles, but you want the player’s view to fill an 800x600 pixel window but only allow viewing a part of the map at a time.
Camera(source_resolution, target_resolution, camera_resolution, behavior=None)¶
Surface that acts as a scrollable view, with optional scaling onto another surface.
- source_resolution (tuple[int, int]) – Maximum size of the environment being portrayed. If you have a map with many inconsistently sized layers, this should be the size of all of those layers flattened onto a single new layer. Anything beyond this size will not be on camera.
- target_resolution (tuple[int, int]) – Resolution to scale up the view of the surface to
- camera_resolution (tuple[int, int]) – Resolution of the view onto the source surface
- behavior (CameraBehavior) – The initial behavior to use for this Camera.
CameraBehaviorthat this Camera uses to control movement.
Scroll to the given focal rectangle using the current behavior.
Parameters: focal_rectangle (pygame.Rect) – Rectangle to possibly update the view position to using the camera’s current behavior
Update the Camera to point to the current scroll position.
Gets the “view” from the current scroll position and camera resolution. That view is used to create a subsurface of the “source subsurface,” scaled to the target_resolution. The new subsurface is then blit to the camera (which is a surface, itself!).
The default camera behavior, which is documented below, puts the focal
rectangle that is given in the top left corner of the view defined
How a camera moves. How it handles boundaries, character movement, etc.
This CameraBehavior, the default, keeps the focal rectangle in the top left of the camera view.
You’ll want to inherit this class when creating a CameraBehavior, including overriding the move method.
Move the camera, keeping the focal rectangle in the top left of the camera view.
This method should be overridden in a child class.
The view area, represented as a Pygame rectangle.
Common camera behaviors¶
Sappho provides some camera behaviors that have some usefulness in common games.
A camera behavior that centers the focal rectangle on the screen.
Will not cause Camera.update() to raise CameraOutOfBounds, because the move logic prevents such from occuring!
Creating a custom camera behavior¶
The move function is called with the
pygame.Rect that represents
the focal point of the view onto the source surface. It returns another
pygame.Rect that represents the view onto the source surface
that should be displayed. The Rect can not go outside the bounds of the
source surface, as when the camera is updated, it creates a subsurface
of the source surface with the Rect that is returned by the move function.
The simplest implementation of a CameraBehavior would be to put the
focal rectangle in the top left. This would be achieved by returning a
Rect that had the x and y attributes set to the x and y attributes of the
focal rectangle, with the width and height of the camera size (specified
camera_resolution property of the
is passed to the
class TopLeftBehavior(CameraBehavior): def move(self, camera, focal_rectangle): return pygame.Rect(focal_rectangle.topleft, camera.camera_resolution)
Hovever, this does not constrain the view to the bounds of the source
surface, meaning that if the focal rectangle goes off the screen, or
it ventures into an area where the focal rectangle’s X or Y position
plus the width of height of the view is greater than the width/height
of the source surface, an error will occur because you can not create
a subsurface of the source surface that goes outside of the bounds of
the source surface. A
CameraOutOfBounds exception is raised
Camera.update() function if the Rect returned by the
move function is out of bounds. This can be useful in some cases, but
for our case, we don’t want to be able to go out of bounds, and instead
should constrain the bounds of the view to the surface:
class TopLeftBehavior(CameraBehavior): def move(self, camera, focal_rectangle): x = focal_rectangle.x y = focal_rectangle.y # Make sure we don't go off the top or left of the source surface if x < 0: x = 0 if y < 0: y = 0 # Make sure we don't go off the bottom or right of the source surface if x + camera.camera_resolution > camera.source_resolution: x = camera.source_resolution - camera.camera_resolution if y + camera.camera_resolution > camera.source_resolution: y = camera.source_resolution - camera.camera_resolution return pygame.Rect((x, y), camera.camera_resolution)
We now have a complete CameraBehavior that puts the focal rectangle in the top left of the screen without going outside the bounds of the source surface!