2025-10-14 04:56:00 +00:00
# Camera Screen Adaptation System
2025-10-21 12:37:53 +02:00
Adapts your 2D orthographic camera to different aspect ratios while keeping gameplay/UI elements aligned to screen edges. Includes a reference marker for target content width and utilities for edge anchoring.
## Table of Contents
- [What This Solves ](#what-this-solves )
- [Architecture at a Glance ](#architecture-at-a-glance )
- [Quick Start (Code-First) ](#quick-start-code-first )
- [Create and Wire Components in Code ](#create-and-wire-components-in-code )
- [Manual Recalculate / Listen for Changes ](#manual-recalculate--listen-for-changes )
- [Components ](#components )
- [`ScreenReferenceMarker` ](#screenreferencemarker )
- [`CameraScreenAdapter` ](#camerascreenadapter )
- [`EdgeAnchor` ](#edgeanchor )
- [Common Case Studies ](#common-case-studies )
- [HUD Top Bar (safe top margin) ](#hud-top-bar-safe-top-margin )
- [Side Buttons (left/right margins) ](#side-buttons-leftright-margins )
- [Cinemachine Virtual Camera ](#cinemachine-virtual-camera )
- [Tips & Best Practices ](#tips--best-practices )
- [Troubleshooting / FAQ ](#troubleshooting--faq )
- [Paths & Namespaces ](#paths--namespaces )
- [Change Log ](#change-log )
## What This Solves
- Consistent horizontal framing across devices: a fixed target world-space width always fits the screen.
- Stable world-space margins from the physical screen edges for placing HUD/world elements.
- Works with both a regular `Camera` and `Cinemachine` 's `CinemachineCamera` .
## Architecture at a Glance
- Reference: `ScreenReferenceMarker` defines `targetWidth` and world-space margins (`topMargin` , `bottomMargin` , `leftMargin` , `rightMargin` ).
- Adapter: `CameraScreenAdapter` computes orthographic size from `targetWidth` and aspect and applies it to the controlled camera. Emits `OnCameraAdjusted` .
- Anchoring: `EdgeAnchor` positions objects relative to the computed screen edges using the same marker margins.
## Quick Start (Code-First)
### Create and Wire Components in Code
```csharp
using AppleHillsCamera;
using UnityEngine;
public class CameraAdaptationBootstrap : MonoBehaviour
{
[SerializeField] private Camera mainCamera; // assign in inspector or find at runtime
private void Awake()
{
// 1) Create/locate the marker
var markerGO = new GameObject("ScreenReferenceMarker");
var marker = markerGO.AddComponent< ScreenReferenceMarker > ();
marker.targetWidth = 16f; // your desired world-space width
marker.topMargin = 1f; // tune margins for your HUD
// 2) Set up the adapter on your camera
var adapter = mainCamera.gameObject.AddComponent< CameraScreenAdapter > ();
adapter.referenceMarker = marker;
adapter.adjustOnStart = true;
adapter.adjustOnScreenResize = true;
// 3) Anchor a sample HUD object to the top edge
var hud = GameObject.CreatePrimitive(PrimitiveType.Quad);
var anchor = hud.AddComponent< EdgeAnchor > ();
anchor.referenceMarker = marker;
anchor.anchor = EdgeAnchor.AnchorEdge.Top;
anchor.additionalOffset = 0.25f; // extra spacing from the top margin
anchor.continuousUpdate = true; // keep tracking when aspect changes
}
}
```
### Manual Recalculate / Listen for Changes
```csharp
using AppleHillsCamera;
using UnityEngine;
public class CameraAdaptationHooks : MonoBehaviour
{
[SerializeField] private CameraScreenAdapter adapter;
private void OnEnable()
{
// Listen when the camera size is applied
adapter.OnCameraAdjusted += OnAdjusted;
}
private void OnDisable()
{
adapter.OnCameraAdjusted -= OnAdjusted;
}
public void ForceRecalculateNow()
{
adapter.AdjustCamera();
}
private void OnAdjusted()
{
Debug.Log("Camera adjusted to match target width.");
// Reposition custom elements if you don’ t use EdgeAnchor
}
}
```
2025-10-14 04:56:00 +00:00
## Components
2025-10-21 12:37:53 +02:00
### `ScreenReferenceMarker`
Defines the reference sizes and margins used by both the adapter and anchors.
Key fields:
- `targetWidth` (float): world-space width that should fully fit the viewport.
- `topMargin` , `bottomMargin` , `leftMargin` , `rightMargin` (float): world-space distances from the corresponding screen edges.
- Scene gizmos: visualizes width line, screen rectangle, and margin guides in the editor.
Typical setup:
- Place at the world-space center of your playable area or camera focus.
- Tune margins to match your HUD/world layout needs.
### `CameraScreenAdapter`
Computes and applies orthographic size to a `Camera` or `CinemachineCamera` so that the screen horizontally fits `targetWidth` .
Highlights:
- Fields: `referenceMarker` , `adjustOnStart` , `adjustOnScreenResize` .
- Event: `OnCameraAdjusted` fires after a size update.
- Works with built-in `Camera` (must be orthographic) or with `CinemachineCamera` .
Formula:
- `orthoSize = (targetWidth / 2f) * (Screen.height / Screen.width)` .
Public helpers:
- `AdjustCamera()` — recalculate and apply now.
- `GetControlledCamera()` — returns the underlying `Camera` instance.
### `EdgeAnchor`
Anchors a `Transform` to a chosen screen edge using the same marker margins.
Common fields (names based on code):
- `referenceMarker` (`ScreenReferenceMarker` )
- `anchor` (`EdgeAnchor.AnchorEdge` ): `Top` , `Bottom` , `Left` , `Right`
- `additionalOffset` (float): extra spacing beyond the margin
- `continuousUpdate` (bool): update every frame and on camera adjustments
Usage tips:
- Use `continuousUpdate` for elements that must track aspect changes at runtime.
- Combine with local offsets/parenting for precise UI/HUD placements in world space.
## Common Case Studies
### HUD Top Bar (safe top margin)
- Set `marker.topMargin` to the vertical padding you want from the top edge.
- Add `EdgeAnchor` to your top bar root:
```csharp
anchor.anchor = EdgeAnchor.AnchorEdge.Top;
anchor.additionalOffset = 0.1f; // small breathing room
```
- Keep `continuousUpdate = true` for device rotation/platform switches.
### Side Buttons (left/right margins)
- For a left button column:
```csharp
anchor.anchor = EdgeAnchor.AnchorEdge.Left;
anchor.additionalOffset = 0.2f;
```
- Mirror for right side with `Right` .
- Adjust `marker.leftMargin/rightMargin` to push them inward safely.
### Cinemachine Virtual Camera
- Add `CameraScreenAdapter` to the GameObject with `CinemachineCamera` .
- The adapter detects Cinemachine and writes to `Lens.OrthographicSize` .
- Everything else (margins and `EdgeAnchor` ) works the same.
## Tips & Best Practices
- Pick a `targetWidth` that matches the core gameplay area horizontally; verify extremes (16:9, 19.5:9, 4:3).
- Prefer `EdgeAnchor` for HUD/world labels instead of manual scripts—anchors auto-update on resize and on `OnCameraAdjusted` .
- For one-off bespoke layouts, listen to `OnCameraAdjusted` and move objects yourself.
- Ensure regular cameras are set to `orthographic` ; the adapter warns if not.
## Troubleshooting / FAQ
- My camera didn’ t change size:
- Ensure `referenceMarker` is assigned.
- For built-in `Camera` , confirm `orthographic` is enabled.
- If using Cinemachine, verify the component is `CinemachineCamera` on the same GameObject.
- Anchored objects are offset oddly:
- Check `additionalOffset` and your object’ s pivot/bounds.
- Verify marker margins and that the marker sits at the world center you expect.
- It works in Play but gizmos look wrong in Scene:
- Scene gizmos approximate using Scene/Game view sizes; rely on Play Mode for truth.
## Paths & Namespaces
- Scripts: `Assets/Scripts/AppleHillsCamera/`
- `ScreenReferenceMarker.cs`
- `CameraScreenAdapter.cs`
- `EdgeAnchor.cs`
- Namespace: `AppleHillsCamera`
## Change Log
- v1.1: Added Table of Contents, code-first snippets, case studies, and aligned terms with actual APIs (`OnCameraAdjusted` , Cinemachine support).
- v1.0: Original overview and setup guide.