Files
AppleHillsProduction/docs/camera_adaptation_readme.md

197 lines
7.7 KiB
Markdown
Raw Normal View History

# 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 dont use EdgeAnchor
}
}
```
## 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 didnt 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 objects 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.