Add horizontal camera scaling for devices

This commit is contained in:
Michal Pikulski
2025-12-18 15:07:27 +01:00
parent b2bc77674d
commit 61f6da7a7d
7 changed files with 326 additions and 32 deletions

View File

@@ -0,0 +1,84 @@
using UnityEngine;
using UnityEditor;
using AppleHillsCamera;
namespace Editor.CustomEditorsAndDrawers
{
/// <summary>
/// Custom editor for CameraScreenAdapter component.
/// Shows scaling mode info and provides helper buttons.
/// </summary>
[CustomEditor(typeof(CameraScreenAdapter))]
public class CameraScreenAdapterEditor : UnityEditor.Editor
{
private SerializedProperty _referenceMarkerProp;
private SerializedProperty _adjustOnStartProp;
private SerializedProperty _adjustOnScreenResizeProp;
private SerializedProperty _debugLoggingProp;
private void OnEnable()
{
_referenceMarkerProp = serializedObject.FindProperty("referenceMarker");
_adjustOnStartProp = serializedObject.FindProperty("adjustOnStart");
_adjustOnScreenResizeProp = serializedObject.FindProperty("adjustOnScreenResize");
_debugLoggingProp = serializedObject.FindProperty("debugLogging");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
CameraScreenAdapter adapter = (CameraScreenAdapter)target;
// Reference Marker
EditorGUILayout.PropertyField(_referenceMarkerProp);
// Show current scaling mode info if reference marker is assigned
if (adapter.referenceMarker != null)
{
EditorGUILayout.Space(5);
ScreenReferenceMarker.ScalingMode mode = adapter.referenceMarker.scalingMode;
string modeStr = mode == ScreenReferenceMarker.ScalingMode.Width ? "Width" : "Height";
EditorGUILayout.HelpBox(
$"Current Scaling Mode: {modeStr}\n" +
(mode == ScreenReferenceMarker.ScalingMode.Width
? $"Target Width: {adapter.referenceMarker.targetWidth:F2} units"
: $"Target Height: {adapter.referenceMarker.targetHeight:F2} units"),
MessageType.Info
);
}
else
{
EditorGUILayout.Space(5);
EditorGUILayout.HelpBox(
"Assign a ScreenReferenceMarker to configure camera scaling.",
MessageType.Warning
);
}
EditorGUILayout.Space(10);
// Settings
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_adjustOnStartProp);
EditorGUILayout.PropertyField(_adjustOnScreenResizeProp);
EditorGUILayout.PropertyField(_debugLoggingProp);
EditorGUILayout.Space(10);
// Manual adjustment button
GUI.enabled = adapter.referenceMarker != null;
if (GUILayout.Button("Adjust Camera Now"))
{
adapter.AdjustCamera();
SceneView.RepaintAll(); // Refresh scene view to show changes
}
GUI.enabled = true;
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 534f6a2da4584452b0df63f25d0d95df
timeCreated: 1766065528

View File

@@ -0,0 +1,105 @@
using UnityEngine;
using UnityEditor;
using AppleHillsCamera;
namespace Editor.CustomEditorsAndDrawers
{
/// <summary>
/// Custom editor for ScreenReferenceMarker component.
/// Shows only relevant fields based on the selected scaling mode.
/// </summary>
[CustomEditor(typeof(ScreenReferenceMarker))]
public class ScreenReferenceMarkerEditor : UnityEditor.Editor
{
private SerializedProperty _scalingModeProp;
private SerializedProperty _targetWidthProp;
private SerializedProperty _targetHeightProp;
private SerializedProperty _topMarginProp;
private SerializedProperty _bottomMarginProp;
private SerializedProperty _leftMarginProp;
private SerializedProperty _rightMarginProp;
private SerializedProperty _gizmoColorProp;
private SerializedProperty _screenEdgeColorProp;
private SerializedProperty _showVerticalMarginsProp;
private SerializedProperty _showHorizontalMarginsProp;
private void OnEnable()
{
_scalingModeProp = serializedObject.FindProperty("scalingMode");
_targetWidthProp = serializedObject.FindProperty("targetWidth");
_targetHeightProp = serializedObject.FindProperty("targetHeight");
_topMarginProp = serializedObject.FindProperty("topMargin");
_bottomMarginProp = serializedObject.FindProperty("bottomMargin");
_leftMarginProp = serializedObject.FindProperty("leftMargin");
_rightMarginProp = serializedObject.FindProperty("rightMargin");
_gizmoColorProp = serializedObject.FindProperty("gizmoColor");
_screenEdgeColorProp = serializedObject.FindProperty("screenEdgeColor");
_showVerticalMarginsProp = serializedObject.FindProperty("showVerticalMargins");
_showHorizontalMarginsProp = serializedObject.FindProperty("showHorizontalMargins");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
// Scaling Mode
EditorGUILayout.PropertyField(_scalingModeProp);
EditorGUILayout.Space(5);
// Reference Dimensions Header
EditorGUILayout.LabelField("Reference Dimensions", EditorStyles.boldLabel);
// Show appropriate dimension field based on scaling mode
ScreenReferenceMarker.ScalingMode mode = (ScreenReferenceMarker.ScalingMode)_scalingModeProp.enumValueIndex;
if (mode == ScreenReferenceMarker.ScalingMode.Width)
{
EditorGUILayout.PropertyField(_targetWidthProp, new GUIContent(
"Target Width",
"The target width that should match the screen width"
));
// Show info about height
EditorGUILayout.HelpBox(
"Height will automatically adjust based on screen aspect ratio.",
MessageType.Info
);
}
else // ScalingMode.Height
{
EditorGUILayout.PropertyField(_targetHeightProp, new GUIContent(
"Target Height",
"The target height that should match the screen height"
));
// Show info about width
EditorGUILayout.HelpBox(
"Width will automatically adjust based on screen aspect ratio.",
MessageType.Info
);
}
EditorGUILayout.Space(10);
// Margins
EditorGUILayout.LabelField("Margins", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_topMarginProp);
EditorGUILayout.PropertyField(_bottomMarginProp);
EditorGUILayout.PropertyField(_leftMarginProp);
EditorGUILayout.PropertyField(_rightMarginProp);
EditorGUILayout.Space(10);
// Visualization
EditorGUILayout.LabelField("Visualization", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(_gizmoColorProp);
EditorGUILayout.PropertyField(_screenEdgeColorProp);
EditorGUILayout.PropertyField(_showVerticalMarginsProp);
EditorGUILayout.PropertyField(_showHorizontalMarginsProp);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9988ac8e5878470997a08ecb42697daf
timeCreated: 1766065516

View File

@@ -820,7 +820,7 @@ Transform:
m_GameObject: {fileID: 941621855} m_GameObject: {fileID: 941621855}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -14.66, y: 0, z: 0} m_LocalPosition: {x: -21.326666, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
@@ -872,6 +872,7 @@ MonoBehaviour:
OnPlayerDamaged: OnPlayerDamaged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
flapCooldown: 0.15
--- !u!114 &941621860 --- !u!114 &941621860
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -1314,7 +1315,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3058fe4801134fea916ad685f924668f, type: 3} m_Script: {fileID: 11500000, guid: 3058fe4801134fea916ad685f924668f, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: AppleHillsScripts::AppleHillsCamera.ScreenReferenceMarker m_EditorClassIdentifier: AppleHillsScripts::AppleHillsCamera.ScreenReferenceMarker
scalingMode: 1
targetWidth: 40 targetWidth: 40
targetHeight: 30.21
topMargin: 0.2 topMargin: 0.2
bottomMargin: 0.2 bottomMargin: 0.2
leftMargin: 0.2 leftMargin: 0.2
@@ -2021,6 +2024,7 @@ MonoBehaviour:
referenceMarker: {fileID: 1143700529} referenceMarker: {fileID: 1143700529}
adjustOnStart: 1 adjustOnStart: 1
adjustOnScreenResize: 1 adjustOnScreenResize: 1
debugLogging: 0
--- !u!1 &2116132838 --- !u!1 &2116132838
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -20,6 +20,9 @@ namespace AppleHillsCamera
[Tooltip("Whether to adjust the camera automatically when the screen size changes")] [Tooltip("Whether to adjust the camera automatically when the screen size changes")]
public bool adjustOnScreenResize = true; public bool adjustOnScreenResize = true;
[Tooltip("Enable debug logging")]
public bool debugLogging;
// Event that other components can subscribe to when camera is adjusted // Event that other components can subscribe to when camera is adjusted
public event Action OnCameraAdjusted; public event Action OnCameraAdjusted;
@@ -71,7 +74,7 @@ namespace AppleHillsCamera
} }
/// <summary> /// <summary>
/// Manually trigger camera adjustment to match the reference width. /// Manually trigger camera adjustment to match the reference width or height.
/// </summary> /// </summary>
public void AdjustCamera() public void AdjustCamera()
{ {
@@ -81,13 +84,34 @@ namespace AppleHillsCamera
return; return;
} }
// Calculate the orthographic size based on the target width and screen aspect ratio float orthoSize;
float targetWidth = referenceMarker.targetWidth;
float screenAspect = (float)Screen.height / Screen.width;
// Orthographic size is half the height, so we calculate: if (referenceMarker.scalingMode == ScreenReferenceMarker.ScalingMode.Width)
// orthoSize = (targetWidth / 2) * (screenHeight / screenWidth) {
float orthoSize = (targetWidth / 2f) * screenAspect; // Calculate the orthographic size based on the target width and screen aspect ratio
float targetWidth = referenceMarker.targetWidth;
float screenAspect = (float)Screen.height / Screen.width;
// Orthographic size is half the height, so we calculate:
// orthoSize = (targetWidth / 2) * (screenHeight / screenWidth)
orthoSize = (targetWidth / 2f) * screenAspect;
if (debugLogging)
{
Logging.Debug($"CameraScreenAdapter: Scaling by Width - targetWidth={targetWidth:F2}, aspect={screenAspect:F2}, orthoSize={orthoSize:F2}");
}
}
else // ScalingMode.Height
{
// When scaling by height, the orthographic size directly matches half the target height
float targetHeight = referenceMarker.targetHeight;
orthoSize = targetHeight / 2f;
if (debugLogging)
{
Logging.Debug($"CameraScreenAdapter: Scaling by Height - targetHeight={targetHeight:F2}, orthoSize={orthoSize:F2}");
}
}
// Apply the calculated size to the camera // Apply the calculated size to the camera
if (_usingCinemachine) if (_usingCinemachine)
@@ -96,7 +120,11 @@ namespace AppleHillsCamera
var lens = _virtualCamera.Lens; var lens = _virtualCamera.Lens;
lens.OrthographicSize = orthoSize; lens.OrthographicSize = orthoSize;
_virtualCamera.Lens = lens; _virtualCamera.Lens = lens;
Logging.Debug($"Cinemachine Camera adapted: Width={targetWidth}, Aspect={screenAspect:F2}, OrthoSize={orthoSize:F2}");
if (debugLogging)
{
Logging.Debug($"Cinemachine Camera adapted: OrthoSize={orthoSize:F2}");
}
} }
else else
{ {
@@ -104,7 +132,11 @@ namespace AppleHillsCamera
if (_regularCamera.orthographic) if (_regularCamera.orthographic)
{ {
_regularCamera.orthographicSize = orthoSize; _regularCamera.orthographicSize = orthoSize;
Logging.Debug($"Camera adapted: Width={targetWidth}, Aspect={screenAspect:F2}, OrthoSize={orthoSize:F2}");
if (debugLogging)
{
Logging.Debug($"Camera adapted: OrthoSize={orthoSize:F2}");
}
} }
else else
{ {

View File

@@ -8,11 +8,24 @@ namespace AppleHillsCamera
/// </summary> /// </summary>
public class ScreenReferenceMarker : MonoBehaviour public class ScreenReferenceMarker : MonoBehaviour
{ {
[Header("Horizontal Reference")] public enum ScalingMode
[Tooltip("The target width that should match the screen width")] {
Width,
Height
}
[Header("Scaling Mode")]
[Tooltip("Whether to scale the camera based on width or height")]
public ScalingMode scalingMode = ScalingMode.Width;
[Header("Reference Dimensions")]
[Tooltip("The target width that should match the screen width (used when scaling by width)")]
public float targetWidth = 10f; public float targetWidth = 10f;
[Header("Vertical References")] [Tooltip("The target height that should match the screen height (used when scaling by height)")]
public float targetHeight = 5f;
[Header("Margins")]
[Tooltip("Distance from top of screen to use for anchoring")] [Tooltip("Distance from top of screen to use for anchoring")]
public float topMargin = 1f; public float topMargin = 1f;
@@ -49,20 +62,8 @@ namespace AppleHillsCamera
Vector3 position = transform.position; Vector3 position = transform.position;
// Draw the width reference // Calculate visual screen edges based on scaling mode and actual camera viewport
Vector3 left = position + Vector3.left * (targetWidth / 2f); float halfWidth;
Vector3 right = position + Vector3.right * (targetWidth / 2f);
Gizmos.DrawLine(left, right);
// Draw vertical endpoints
float endCapSize = 0.5f;
Gizmos.DrawLine(left, left + Vector3.up * endCapSize);
Gizmos.DrawLine(left, left + Vector3.down * endCapSize);
Gizmos.DrawLine(right, right + Vector3.up * endCapSize);
Gizmos.DrawLine(right, right + Vector3.down * endCapSize);
// Calculate visual screen edges based on actual camera viewport
float halfWidth = targetWidth / 2f;
float halfHeight; float halfHeight;
// Try to get camera references in the preferred order // Try to get camera references in the preferred order
@@ -71,14 +72,37 @@ namespace AppleHillsCamera
Camera mainCamera = Camera.main; Camera mainCamera = Camera.main;
if (mainCamera != null && mainCamera.orthographic) if (mainCamera != null && mainCamera.orthographic)
{ {
// Use the main camera's actual orthographic size for the height if (scalingMode == ScalingMode.Width)
halfHeight = mainCamera.orthographicSize; {
// When scaling by width, the width is fixed and height varies
halfWidth = targetWidth / 2f;
// Use the main camera's actual orthographic size for the height
halfHeight = mainCamera.orthographicSize;
}
else // ScalingMode.Height
{
// When scaling by height, the height is fixed and width varies
halfHeight = targetHeight / 2f;
// Calculate width based on camera's aspect ratio
float screenAspect = (float)Screen.width / Screen.height;
halfWidth = halfHeight * screenAspect;
}
} }
else else
{ {
// 2. Use Game/Simulator window resolution // 2. Use Game/Simulator window resolution
float gameViewAspect = (float)Screen.height / Screen.width; float gameViewAspect = (float)Screen.height / Screen.width;
halfHeight = halfWidth * gameViewAspect;
if (scalingMode == ScalingMode.Width)
{
halfWidth = targetWidth / 2f;
halfHeight = halfWidth * gameViewAspect;
}
else // ScalingMode.Height
{
halfHeight = targetHeight / 2f;
halfWidth = halfHeight / gameViewAspect;
}
// 3. Fallback to the scene view camera if needed // 3. Fallback to the scene view camera if needed
UnityEditor.SceneView sceneView = UnityEditor.SceneView.lastActiveSceneView; UnityEditor.SceneView sceneView = UnityEditor.SceneView.lastActiveSceneView;
@@ -86,10 +110,49 @@ namespace AppleHillsCamera
{ {
// Use the scene view camera's aspect ratio instead // Use the scene view camera's aspect ratio instead
float sceneAspect = sceneView.camera.pixelHeight / (float)sceneView.camera.pixelWidth; float sceneAspect = sceneView.camera.pixelHeight / (float)sceneView.camera.pixelWidth;
halfHeight = halfWidth * sceneAspect;
if (scalingMode == ScalingMode.Width)
{
halfHeight = halfWidth * sceneAspect;
}
else // ScalingMode.Height
{
float sceneAspectInv = sceneView.camera.pixelWidth / (float)sceneView.camera.pixelHeight;
halfWidth = halfHeight * sceneAspectInv;
}
} }
} }
// Draw the reference dimension indicator based on scaling mode
if (scalingMode == ScalingMode.Width)
{
// Draw the width reference (horizontal line)
Vector3 left = position + Vector3.left * halfWidth;
Vector3 right = position + Vector3.right * halfWidth;
Gizmos.DrawLine(left, right);
// Draw vertical endpoints
float endCapSize = 0.5f;
Gizmos.DrawLine(left, left + Vector3.up * endCapSize);
Gizmos.DrawLine(left, left + Vector3.down * endCapSize);
Gizmos.DrawLine(right, right + Vector3.up * endCapSize);
Gizmos.DrawLine(right, right + Vector3.down * endCapSize);
}
else // ScalingMode.Height
{
// Draw the height reference (vertical line)
Vector3 top = position + Vector3.up * halfHeight;
Vector3 bottom = position + Vector3.down * halfHeight;
Gizmos.DrawLine(top, bottom);
// Draw horizontal endpoints
float endCapSize = 0.5f;
Gizmos.DrawLine(top, top + Vector3.left * endCapSize);
Gizmos.DrawLine(top, top + Vector3.right * endCapSize);
Gizmos.DrawLine(bottom, bottom + Vector3.left * endCapSize);
Gizmos.DrawLine(bottom, bottom + Vector3.right * endCapSize);
}
// Screen edge positions // Screen edge positions
Vector3 topEdge = position + Vector3.up * halfHeight; Vector3 topEdge = position + Vector3.up * halfHeight;
Vector3 bottomEdge = position + Vector3.down * halfHeight; Vector3 bottomEdge = position + Vector3.down * halfHeight;