Files
AppleHillsProduction/docs/camera_adaptation_readme.md
2025-10-21 12:37:57 +02:00

197 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<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
### `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.