197 lines
7.7 KiB
Markdown
197 lines
7.7 KiB
Markdown
# 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 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.
|