Game Camera System
One service that knows every camera in the scene, switches the active one without breaking your rigs, and lays out split-screen automatically.
What the system is for
Cameras in Unity start simple: one Main Camera, one tag, Camera.main everywhere. Then the project grows a menu camera, a gameplay camera, a cutscene rig, maybe a Cinemachine setup, and suddenly half the codebase is toggling GameObjects and hoping the right camera wins. Add local multiplayer and the viewport math becomes its own feature.
The Game Camera system in Serenity turns all of that into one contract. It keeps a registry of every camera in the game, exposes explicit active-camera switching that cooperates with Cinemachine and custom rigs, and handles local-multiplayer split-screen layouts for you.
The Unity problem
Most projects manage cameras by enabling and disabling GameObjects. That works until a camera lives inside a rig with other scripts: disabling the object kills the CinemachineBrain, the audio listener or the shake component along with the camera. So teams write special cases per rig, and switching cameras becomes something only one person on the team knows how to do safely.
Discovery is the other half of the problem. Cameras that start disabled, or that live in additively loaded scenes, are invisible to Camera.main and to naive FindObjectOfType calls. And when local multiplayer arrives, someone has to write the Camera.rect layout math, recalculate it every time a player joins or leaves, and keep per-player overrides working.
How Serenity approaches it
Serenity exposes the contract through IGameCameraService in the Application layer. The service keeps a registry of every game camera: cameras are auto-discovered on scene load, including inactive and unreferenced ones, and can also be registered explicitly through the API or with a no-code UnityGameCameraRegistrar component. A UnityGameCameraExclude marker opts a camera out of discovery.
Switching is exclusive and rig-safe: activating a camera disables only the Camera component of the others, never their GameObjects, so a CinemachineBrain or any sibling script keeps running untouched. For local multiplayer, the service computes split-screen Camera.rect layouts automatically from the player count, recalculates them on join and leave, and accepts per-player viewport overrides or a settings asset for custom layouts.
How it fits into Serenity
Game Camera lives in the Serenity.GameCamera namespace, with the service contract IGameCameraService in the Application layer and the Unity-specific implementation in Infrastructure. It is installed by UnitySerenityInstaller right after the global services, so every other system can resolve it through the service locator or dependency injection.
Other Serenity systems build on it instead of reaching for Camera.main. Screen Feedback resolves its shake target through the camera service, cutscenes can hand control to a rig camera and give it back, and Game Mode transitions can switch cameras as part of entering menu or gameplay states.
Practical workflow
- Install the system through UnitySerenityInstaller; no extra scene setup is required for discovery.
- Let scene-load discovery register your cameras, or place a UnityGameCameraRegistrar component for explicit no-code registration.
- Mark helper cameras (thumbnails, reflections, render textures) with UnityGameCameraExclude so they never enter the registry.
- Resolve IGameCameraService and call GetActiveCamera() wherever you previously used Camera.main.
- Switch the active camera through the service when entering menus, gameplay or cutscenes.
- For local multiplayer, enable split-screen and let the service lay out viewports per player, or supply your own overrides.
What you get
- IGameCameraService contract resolved through the service locator or DI
- Camera registry auto-discovered on scene load, including inactive and unreferenced cameras
- Explicit registration API plus a no-code UnityGameCameraRegistrar component
- UnityGameCameraExclude marker to opt cameras out of discovery
- Exclusive active-camera switching that disables only the Camera component, never the GameObject
- Cinemachine-agnostic: brains and rig scripts keep running through switches
- Local-multiplayer split-screen with automatic Camera.rect layouts by player count
- Layouts recalculated on player join and leave, with per-player viewport overrides
- SetActiveCameraOverride to pin a custom rig as the active camera
When to use this
- Projects with more than one camera: menus, gameplay, cutscenes or debug views.
- Cinemachine or custom rig setups where disabling GameObjects breaks the rig.
- Local-multiplayer games that need split-screen without hand-written viewport math.
- Codebases that want to remove Camera.main and static camera helpers in favor of an injectable service.
Related systems
Use Serenity when you want camera management that already cooperates with your rigs, your game modes and your multiplayer setup, but still lets you decide which cameras exist and when they take over.
English
Español
Català