# Camera Screen Adaptation System 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(); 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(); 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(); 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 } } ``` ## Components ### `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.