Working screen anchoring

This commit is contained in:
Michal Pikulski
2025-10-13 16:31:52 +02:00
parent a55ba5e29c
commit 0b966e9976
9 changed files with 436 additions and 92 deletions

View File

@@ -1 +0,0 @@
{"TestSuite":"","Date":0,"Player":{"Development":false,"ScreenWidth":0,"ScreenHeight":0,"ScreenRefreshRate":0,"Fullscreen":false,"Vsync":0,"AntiAliasing":0,"Batchmode":false,"RenderThreadingMode":"MultiThreaded","GpuSkinning":false,"Platform":"","ColorSpace":"","AnisotropicFiltering":"","BlendWeights":"","GraphicsApi":"","ScriptingBackend":"IL2CPP","AndroidTargetSdkVersion":"AndroidApiLevelAuto","AndroidBuildSystem":"Gradle","BuildTarget":"Android","StereoRenderingPath":"MultiPass"},"Hardware":{"OperatingSystem":"","DeviceModel":"","DeviceName":"","ProcessorType":"","ProcessorCount":0,"GraphicsDeviceName":"","SystemMemorySizeMB":0},"Editor":{"Version":"6000.2.6f1","Branch":"6000.2/staging","Changeset":"cc51a95c0300","Date":1758053328},"Dependencies":["com.unity.2d.sprite@1.0.0","com.unity.2d.spriteshape@12.0.1","com.unity.addressables@2.7.3","com.unity.addressables.android@1.0.7","com.unity.cinemachine@3.1.4","com.unity.device-simulator.devices@1.0.0","com.unity.feature.2d@2.0.1","com.unity.film-internal-utilities@0.18.4-preview","com.unity.graphtoolkit@0.4.0-exp.2","com.unity.ide.rider@3.0.38","com.unity.ide.visualstudio@2.0.23","com.unity.inputsystem@1.14.2","com.unity.multiplayer.center@1.0.0","com.unity.render-pipelines.universal@17.2.0","com.unity.timeline@1.8.9","com.unity.ugui@2.0.0","com.unity.modules.accessibility@1.0.0","com.unity.modules.ai@1.0.0","com.unity.modules.androidjni@1.0.0","com.unity.modules.animation@1.0.0","com.unity.modules.assetbundle@1.0.0","com.unity.modules.audio@1.0.0","com.unity.modules.cloth@1.0.0","com.unity.modules.director@1.0.0","com.unity.modules.imageconversion@1.0.0","com.unity.modules.imgui@1.0.0","com.unity.modules.jsonserialize@1.0.0","com.unity.modules.particlesystem@1.0.0","com.unity.modules.physics@1.0.0","com.unity.modules.physics2d@1.0.0","com.unity.modules.screencapture@1.0.0","com.unity.modules.terrain@1.0.0","com.unity.modules.terrainphysics@1.0.0","com.unity.modules.tilemap@1.0.0","com.unity.modules.ui@1.0.0","com.unity.modules.uielements@1.0.0","com.unity.modules.umbra@1.0.0","com.unity.modules.unityanalytics@1.0.0","com.unity.modules.unitywebrequest@1.0.0","com.unity.modules.unitywebrequestassetbundle@1.0.0","com.unity.modules.unitywebrequestaudio@1.0.0","com.unity.modules.unitywebrequesttexture@1.0.0","com.unity.modules.unitywebrequestwww@1.0.0","com.unity.modules.vehicles@1.0.0","com.unity.modules.video@1.0.0","com.unity.modules.vr@1.0.0","com.unity.modules.wind@1.0.0","com.unity.modules.xr@1.0.0","com.unity.modules.subsystems@1.0.0","com.unity.modules.hierarchycore@1.0.0","com.unity.render-pipelines.core@17.2.0","com.unity.shadergraph@17.2.0","com.unity.render-pipelines.universal-config@17.0.3","com.unity.test-framework@1.6.0","com.unity.ext.nunit@2.0.5","com.unity.2d.animation@12.0.2","com.unity.2d.pixel-perfect@5.1.0","com.unity.2d.psdimporter@11.0.1","com.unity.2d.tilemap@1.0.0","com.unity.2d.tilemap.extras@5.0.1","com.unity.2d.aseprite@2.0.1","com.unity.splines@2.8.2","com.unity.profiling.core@1.0.2","com.unity.scriptablebuildpipeline@2.4.2","com.unity.2d.common@11.0.1","com.unity.mathematics@1.3.2","com.unity.searcher@4.9.3","com.unity.burst@1.8.24","com.unity.collections@2.5.7","com.unity.rendering.light-transport@1.0.1","com.unity.settings-manager@2.1.0","com.unity.nuget.mono-cecil@1.11.5","com.unity.test-framework.performance@3.1.0"],"Results":[]}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: cb4b04b706692c14ab819cb590863198
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1 +0,0 @@
{"MeasurementCount":-1}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 4fcd6892d10380341866ac1c8a8c0ed9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -342,17 +342,17 @@ LineRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_Positions:
- {x: -0.15602553, y: 7.6274276, z: 0}
- {x: -0.33293986, y: 6.2028694, z: 0}
- {x: -0.47067532, y: 4.9898887, z: 0}
- {x: -0.569232, y: 3.988484, z: 0}
- {x: -0.6286098, y: 3.1986566, z: 0}
- {x: -0.6488087, y: 2.6204057, z: 0}
- {x: -0.62982893, y: 2.2537322, z: 0}
- {x: -0.57167023, y: 2.0986352, z: 0}
- {x: -0.47433275, y: 2.1551156, z: 0}
- {x: -0.33781648, y: 2.4231722, z: 0}
- {x: -0.16212131, y: 2.9028063, z: 0}
- {x: -0.15602553, y: 4.0749445, z: 0}
- {x: -0.1566351, y: 3.9736378, z: 0}
- {x: -0.1572447, y: 3.8729858, z: 0}
- {x: -0.15785426, y: 3.7729874, z: 0}
- {x: -0.15846384, y: 3.6736438, z: 0}
- {x: -0.15907341, y: 3.5749543, z: 0}
- {x: -0.15968299, y: 3.4769194, z: 0}
- {x: -0.16029257, y: 3.3795385, z: 0}
- {x: -0.16090216, y: 3.2828126, z: 0}
- {x: -0.16151173, y: 3.1867406, z: 0}
- {x: -0.16212131, y: 3.0913231, z: 0}
m_Parameters:
serializedVersion: 3
widthMultiplier: 1
@@ -915,7 +915,7 @@ Transform:
m_GameObject: {fileID: 747976396}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 6.75, z: 0}
m_LocalPosition: {x: 0, y: 3.1975174, z: 0}
m_LocalScale: {x: 0.57574, y: 0.57574, z: 0.57574}
m_ConstrainProportionsScale: 0
m_Children:
@@ -935,6 +935,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d39dbaae819c4a128a11ca60fbbc98c9, type: 3}
m_Name:
m_EditorClassIdentifier:
edgeAnchor: {fileID: 747976407}
--- !u!114 &747976399
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -1119,14 +1120,18 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::AppleHillsCamera.EdgeAnchor
referenceMarker: {fileID: 1651034645}
cameraAdapter: {fileID: 224729335}
anchorEdge: 0
useReferenceMargin: 0
customMargin: 0
customMargin: 2
adjustOnStart: 1
adjustOnScreenResize: 1
adjustOnScreenResize: 0
preserveOtherAxes: 1
accountForObjectSize: 1
showVisualization: 1
visualizationColor: {r: 1, g: 0, b: 0, a: 0.8}
visualizationColor: {r: 1, g: 0, b: 1, a: 1}
showObjectBounds: 1
debugMode: 0
--- !u!1 &824396214
GameObject:
m_ObjectHideFlags: 0
@@ -1362,17 +1367,17 @@ LineRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_Positions:
- {x: -0.15602553, y: 7.6274276, z: 0}
- {x: -0.29288492, y: 6.2025185, z: 0}
- {x: -0.39057457, y: 4.9891615, z: 0}
- {x: -0.44909453, y: 3.9873564, z: 0}
- {x: -0.4684448, y: 3.197105, z: 0}
- {x: -0.44862524, y: 2.6184058, z: 0}
- {x: -0.389636, y: 2.2512593, z: 0}
- {x: -0.2914771, y: 2.0956657, z: 0}
- {x: -0.15414846, y: 2.1516247, z: 0}
- {x: 0.022349834, y: 2.419136, z: 0}
- {x: 0.23801796, y: 2.8982003, z: 0}
- {x: -0.15602553, y: 4.074945, z: 0}
- {x: -0.11662118, y: 3.8796225, z: 0}
- {x: -0.07721684, y: 3.7057445, z: 0}
- {x: -0.03781248, y: 3.5533106, z: 0}
- {x: 0.0015918687, y: 3.4223216, z: 0}
- {x: 0.040996216, y: 3.3127766, z: 0}
- {x: 0.08040057, y: 3.2246757, z: 0}
- {x: 0.11980491, y: 3.1580195, z: 0}
- {x: 0.15920927, y: 3.1128078, z: 0}
- {x: 0.1986136, y: 3.0890403, z: 0}
- {x: 0.23801796, y: 3.0867171, z: 0}
m_Parameters:
serializedVersion: 3
widthMultiplier: 1
@@ -1905,17 +1910,17 @@ LineRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_Positions:
- {x: -0.15602553, y: 7.6274276, z: 0}
- {x: -0.36587217, y: 6.20166, z: 0}
- {x: -0.53654, y: 4.98747, z: 0}
- {x: -0.66802895, y: 3.984856, z: 0}
- {x: -0.76033914, y: 3.1938195, z: 0}
- {x: -0.81347036, y: 2.6143596, z: 0}
- {x: -0.82742286, y: 2.2464767, z: 0}
- {x: -0.80219656, y: 2.090171, z: 0}
- {x: -0.7377914, y: 2.1454425, z: 0}
- {x: -0.6342074, y: 2.4122903, z: 0}
- {x: -0.4914446, y: 2.8907156, z: 0}
- {x: -0.15602553, y: 4.074945, z: 0}
- {x: -0.18956745, y: 3.8764977, z: 0}
- {x: -0.22310936, y: 3.7000232, z: 0}
- {x: -0.25665125, y: 3.5455205, z: 0}
- {x: -0.29019317, y: 3.4129908, z: 0}
- {x: -0.32373506, y: 3.3024333, z: 0}
- {x: -0.35727698, y: 3.213848, z: 0}
- {x: -0.39081886, y: 3.1472356, z: 0}
- {x: -0.4243608, y: 3.1025953, z: 0}
- {x: -0.45790267, y: 3.0799277, z: 0}
- {x: -0.4914446, y: 3.0792325, z: 0}
m_Parameters:
serializedVersion: 3
widthMultiplier: 1
@@ -2445,7 +2450,7 @@ Transform:
m_GameObject: {fileID: 2106431001}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.165, y: 2.509, z: 0}
m_LocalPosition: {x: -0.165, y: 2.697517, z: 0}
m_LocalScale: {x: 0.57574, y: 0.57574, z: 0.57574}
m_ConstrainProportionsScale: 0
m_Children:
@@ -2474,7 +2479,7 @@ MonoBehaviour:
bottleWobble: {fileID: 747976399}
followStiffness: 4
useWobbleOffset: 1
baseY: 2.5
verticalDistance: 0.5
--- !u!114 &2106431004
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@@ -1,5 +1,6 @@
using UnityEngine;
using Unity.Cinemachine;
using System;
namespace AppleHillsCamera
{
@@ -17,6 +18,9 @@ namespace AppleHillsCamera
[Tooltip("Whether to adjust the camera automatically when the screen size changes")]
public bool adjustOnScreenResize = true;
// Event that other components can subscribe to when camera is adjusted
public event Action OnCameraAdjusted;
private Camera _regularCamera;
private CinemachineCamera _virtualCamera;
@@ -104,8 +108,20 @@ namespace AppleHillsCamera
else
{
Debug.LogWarning("CameraScreenAdapter: Regular camera is not in orthographic mode.");
return;
}
}
// Notify subscribers that the camera has been adjusted
OnCameraAdjusted?.Invoke();
}
/// <summary>
/// Gets the camera component being controlled by this adapter
/// </summary>
public Camera GetControlledCamera()
{
return _usingCinemachine ? _virtualCamera.GetComponent<Camera>() : _regularCamera;
}
}
}

View File

@@ -1,4 +1,6 @@
using UnityEngine;
using AppleHills.Core;
using UnityEngine;
using System;
namespace AppleHillsCamera
{
@@ -8,6 +10,9 @@ namespace AppleHillsCamera
[ExecuteInEditMode] // Make it run in the editor
public class EdgeAnchor : MonoBehaviour
{
// Event that fires when the anchor's position is updated
public event Action OnPositionUpdated;
public enum AnchorEdge
{
Top,
@@ -19,6 +24,9 @@ namespace AppleHillsCamera
[Tooltip("Reference marker that defines the screen edges and margins")]
public ScreenReferenceMarker referenceMarker;
[Tooltip("Camera adapter to subscribe to for runtime updates")]
public CameraScreenAdapter cameraAdapter;
[Tooltip("Which screen edge to anchor to")]
public AnchorEdge anchorEdge = AnchorEdge.Top;
@@ -37,18 +45,29 @@ namespace AppleHillsCamera
[Tooltip("Whether to preserve the object's position on other axes")]
public bool preserveOtherAxes = true;
[Tooltip("Whether to account for this object's size in positioning")]
public bool accountForObjectSize = true;
[Header("Visualization")]
[Tooltip("Whether to show the anchor visualization in the editor")]
public bool showVisualization = true;
[Tooltip("Color for the anchor visualization line")]
public Color visualizationColor = new Color(1f, 0f, 0f, 0.8f);
[Tooltip("Show object bounds in visualization")]
public bool showObjectBounds = true;
[Tooltip("Debug mode - print position changes to console")]
public bool debugMode = false;
private Camera _camera;
private int _lastScreenWidth;
private int _lastScreenHeight;
private float _lastOrthoSize = 0f;
private Vector3 _originalPosition;
private bool _initialized = false;
private Bounds _objectBounds;
#if UNITY_EDITOR
private void OnDrawGizmos()
@@ -56,19 +75,39 @@ namespace AppleHillsCamera
if (!showVisualization || referenceMarker == null)
return;
// Draw a line from the object to its anchor point
Vector3 anchorPoint = GetAnchorPoint();
// Find camera if needed
if (_camera == null)
FindCamera();
if (_camera == null)
return;
// Calculate the anchor point (the exact point on the screen edge)
Vector3 anchorPoint = CalculateScreenEdgePoint();
// Save original color
Color originalColor = Gizmos.color;
// Draw line to anchor point
Gizmos.color = visualizationColor;
Gizmos.DrawLine(gameObject.transform.position, anchorPoint);
Gizmos.DrawLine(transform.position, anchorPoint);
// Draw a small sphere at the anchor point
Gizmos.DrawSphere(anchorPoint, 0.1f);
// Draw object bounds if enabled
if (showObjectBounds && accountForObjectSize)
{
Bounds bounds = GetObjectBounds();
if (bounds.size != Vector3.zero)
{
Color boundsColor = visualizationColor;
boundsColor.a *= 0.3f;
Gizmos.color = boundsColor;
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}
// Restore original color
Gizmos.color = originalColor;
}
@@ -78,6 +117,10 @@ namespace AppleHillsCamera
{
_originalPosition = transform.position;
FindCamera();
if (_camera != null)
{
_lastOrthoSize = _camera.orthographicSize;
}
_lastScreenWidth = Screen.width;
_lastScreenHeight = Screen.height;
_initialized = true;
@@ -94,6 +137,12 @@ namespace AppleHillsCamera
_initialized = true;
}
// Subscribe to camera adapter events
if (Application.isPlaying && cameraAdapter != null)
{
cameraAdapter.OnCameraAdjusted += HandleCameraAdjusted;
}
// Adjust position immediately when enabled in editor
#if UNITY_EDITOR
if (!Application.isPlaying)
@@ -103,18 +152,97 @@ namespace AppleHillsCamera
#endif
}
private void OnDisable()
{
// Unsubscribe from camera adapter events
if (cameraAdapter != null)
{
cameraAdapter.OnCameraAdjusted -= HandleCameraAdjusted;
}
}
private void HandleCameraAdjusted()
{
// Update position when camera is adjusted
if (Application.isPlaying)
{
if (debugMode)
{
Debug.Log($"Camera adjusted event received by {gameObject.name}, updating position");
}
// Ensure we have the latest camera reference
FindCamera();
UpdatePosition();
}
}
private void Start()
{
// If no camera adapter was manually set, try to find one in the scene
if (cameraAdapter == null && Application.isPlaying)
{
FindCameraAdapter();
}
// Ensure we're subscribed to camera adapter events
if (cameraAdapter != null && Application.isPlaying)
{
cameraAdapter.OnCameraAdjusted -= HandleCameraAdjusted; // Remove any duplicate subscriptions
cameraAdapter.OnCameraAdjusted += HandleCameraAdjusted; // Subscribe
}
if (adjustOnStart && Application.isPlaying)
{
UpdatePosition();
}
}
private void FindCameraAdapter()
{
// Try to find the camera adapter in the scene
var adapters = FindObjectsOfType<CameraScreenAdapter>();
if (adapters != null && adapters.Length > 0)
{
// Prioritize any adapter that's on the same camera we're using
foreach (var adapter in adapters)
{
if (_camera != null && adapter.GetControlledCamera() == _camera)
{
cameraAdapter = adapter;
Debug.Log($"EdgeAnchor on {gameObject.name} auto-connected to CameraScreenAdapter on {cameraAdapter.gameObject.name}");
return;
}
}
// If no matching camera found, use the first one
cameraAdapter = adapters[0];
Debug.Log($"EdgeAnchor on {gameObject.name} auto-connected to CameraScreenAdapter on {cameraAdapter.gameObject.name}");
}
}
private void Update()
{
bool shouldUpdate = false;
// Check if we have a valid camera
if (_camera == null)
{
FindCamera();
if (_camera != null) shouldUpdate = true;
}
// Check if camera's ortho size has changed
if (_camera != null && _camera.orthographicSize != _lastOrthoSize)
{
if (debugMode)
{
Debug.Log($"{gameObject.name}: Camera ortho size changed from {_lastOrthoSize} to {_camera.orthographicSize}");
}
_lastOrthoSize = _camera.orthographicSize;
shouldUpdate = true;
}
// Update if screen size has changed
if (adjustOnScreenResize &&
(Screen.width != _lastScreenWidth || Screen.height != _lastScreenHeight))
@@ -141,6 +269,18 @@ namespace AppleHillsCamera
private void FindCamera()
{
Camera prevCamera = _camera;
// First check if we have a camera adapter reference
if (cameraAdapter != null)
{
_camera = cameraAdapter.GetControlledCamera();
if (_camera != null)
{
return;
}
}
// Look for the main camera
_camera = Camera.main;
@@ -154,6 +294,43 @@ namespace AppleHillsCamera
{
Debug.LogError("EdgeAnchor: No camera found in the scene.");
}
else if (_camera != prevCamera && debugMode)
{
Debug.Log($"{gameObject.name}: Camera reference updated to {_camera.name}");
}
}
/// <summary>
/// Get the combined bounds of all renderers on this object and its children
/// </summary>
private Bounds GetObjectBounds()
{
Bounds bounds = new Bounds(transform.position, Vector3.zero);
// Get all renderers in this object and its children
Renderer[] renderers = GetComponentsInChildren<Renderer>();
if (renderers.Length > 0)
{
// Start with the first renderer's bounds
bounds = renderers[0].bounds;
// Expand to include all other renderers
for (int i = 1; i < renderers.Length; i++)
{
bounds.Encapsulate(renderers[i].bounds);
}
}
else
{
// No renderers found, create a small placeholder bounds
bounds = new Bounds(transform.position, new Vector3(0.1f, 0.1f, 0.1f));
}
// Cache the bounds
_objectBounds = bounds;
return bounds;
}
/// <summary>
@@ -176,7 +353,7 @@ namespace AppleHillsCamera
// Get the margin value to use
float margin = GetMarginValue();
// Calculate the new position based on anchor edge
// Calculate the new position based on anchor edge and object size
Vector3 newPosition = CalculateAnchoredPosition(margin);
// If preserving other axes, keep their original values
@@ -198,7 +375,21 @@ namespace AppleHillsCamera
}
// Apply the new position
if (debugMode && Vector3.Distance(transform.position, newPosition) > 0.01f)
{
Debug.Log($"{gameObject.name} position updated: {transform.position} -> {newPosition}, Camera OrthoSize: {_camera.orthographicSize}");
}
transform.position = newPosition;
// Notify listeners that the position has been updated
OnPositionUpdated?.Invoke();
// Store the current ortho size for change detection
if (_camera != null)
{
_lastOrthoSize = _camera.orthographicSize;
}
}
private float GetMarginValue()
@@ -225,36 +416,73 @@ namespace AppleHillsCamera
private Vector3 CalculateAnchoredPosition(float margin)
{
// Get the screen edges in world coordinates
if (_camera == null)
return transform.position;
// Always get the CURRENT camera properties to ensure we have latest values
float cameraOrthoSize = _camera.orthographicSize;
float screenAspect = (float)Screen.width / Screen.height;
float screenHeight = cameraOrthoSize * 2f;
float screenWidth = screenHeight * screenAspect;
Vector3 cameraPosition = _camera.transform.position;
Vector3 newPosition = transform.position;
// Calculate object size offset if needed
float offsetX = 0f;
float offsetY = 0f;
if (accountForObjectSize)
{
Bounds bounds = GetObjectBounds();
Vector3 extents = bounds.extents; // Half the size
Vector3 centerOffset = bounds.center - transform.position; // Offset from pivot to center
switch (anchorEdge)
{
case AnchorEdge.Top:
// For top edge, offset is negative (moving down) by the top extent
offsetY = -extents.y - centerOffset.y;
break;
case AnchorEdge.Bottom:
// For bottom edge, offset is positive (moving up) by the bottom extent
offsetY = extents.y - centerOffset.y;
break;
case AnchorEdge.Left:
// For left edge, offset is positive (moving right) by the left extent
offsetX = extents.x - centerOffset.x;
break;
case AnchorEdge.Right:
// For right edge, offset is negative (moving left) by the right extent
offsetX = -extents.x - centerOffset.x;
break;
}
}
switch (anchorEdge)
{
case AnchorEdge.Top:
// Position from the top of the screen
newPosition.y = cameraPosition.y + cameraOrthoSize - margin;
// When margin is 0, object's top edge is exactly at the top screen edge
newPosition.y = cameraPosition.y + cameraOrthoSize - margin + offsetY;
break;
case AnchorEdge.Bottom:
// Position from the bottom of the screen
newPosition.y = cameraPosition.y - cameraOrthoSize + margin;
// When margin is 0, object's bottom edge is exactly at the bottom screen edge
newPosition.y = cameraPosition.y - cameraOrthoSize + margin + offsetY;
break;
case AnchorEdge.Left:
// Position from the left of the screen
newPosition.x = cameraPosition.x - (screenWidth / 2f) + margin;
// When margin is 0, object's left edge is exactly at the left screen edge
newPosition.x = cameraPosition.x - (screenWidth / 2f) + margin + offsetX;
break;
case AnchorEdge.Right:
// Position from the right of the screen
newPosition.x = cameraPosition.x + (screenWidth / 2f) - margin;
// When margin is 0, object's right edge is exactly at the right screen edge
newPosition.x = cameraPosition.x + (screenWidth / 2f) - margin + offsetX;
break;
}
@@ -262,16 +490,13 @@ namespace AppleHillsCamera
}
/// <summary>
/// Gets the anchor point on the edge for visualization
/// Calculates the exact point on the screen edge for visualization purposes
/// </summary>
private Vector3 GetAnchorPoint()
private Vector3 CalculateScreenEdgePoint()
{
if (_camera == null)
{
FindCamera();
if (_camera == null) return transform.position;
}
return transform.position;
// Get the screen edges in world coordinates
float cameraOrthoSize = _camera.orthographicSize;
float screenAspect = (float)Screen.width / Screen.height;
@@ -279,32 +504,46 @@ namespace AppleHillsCamera
float screenWidth = screenHeight * screenAspect;
Vector3 cameraPosition = _camera.transform.position;
Vector3 anchorPoint = transform.position;
Vector3 objectPosition = transform.position;
// Calculate the point exactly on the screen edge that corresponds to the object's anchor
switch (anchorEdge)
{
case AnchorEdge.Top:
// Anchor at top edge with same X as the object
anchorPoint.y = cameraPosition.y + cameraOrthoSize;
break;
// Point on top edge with same X coordinate as the object
return new Vector3(
objectPosition.x,
cameraPosition.y + cameraOrthoSize,
objectPosition.z
);
case AnchorEdge.Bottom:
// Anchor at bottom edge with same X as the object
anchorPoint.y = cameraPosition.y - cameraOrthoSize;
break;
// Point on bottom edge with same X coordinate as the object
return new Vector3(
objectPosition.x,
cameraPosition.y - cameraOrthoSize,
objectPosition.z
);
case AnchorEdge.Left:
// Anchor at left edge with same Y as the object
anchorPoint.x = cameraPosition.x - (screenWidth / 2f);
break;
// Point on left edge with same Y coordinate as the object
return new Vector3(
cameraPosition.x - (screenWidth / 2f),
objectPosition.y,
objectPosition.z
);
case AnchorEdge.Right:
// Anchor at right edge with same Y as the object
anchorPoint.x = cameraPosition.x + (screenWidth / 2f);
break;
// Point on right edge with same Y coordinate as the object
return new Vector3(
cameraPosition.x + (screenWidth / 2f),
objectPosition.y,
objectPosition.z
);
default:
return objectPosition;
}
return anchorPoint;
}
}
}

View File

@@ -1,6 +1,7 @@
using UnityEngine;
using AppleHills.Core.Settings;
using Input;
using AppleHillsCamera;
namespace Minigames.DivingForPictures
{
@@ -10,6 +11,10 @@ namespace Minigames.DivingForPictures
/// </summary>
public class PlayerController : MonoBehaviour, ITouchInputConsumer
{
[Tooltip("Reference to the edge anchor that this player should follow for Y position")]
[SerializeField] private EdgeAnchor edgeAnchor;
// Settings reference
private IDivingMinigameSettings _settings;
@@ -42,6 +47,38 @@ namespace Minigames.DivingForPictures
_targetFingerX = transform.position.x;
_isTouchActive = false;
// Try to find edge anchor if not assigned
if (edgeAnchor == null)
{
// First try to find edge anchor on the same object or parent
edgeAnchor = GetComponentInParent<EdgeAnchor>();
// If not found, find any edge anchor in the scene
if (edgeAnchor == null)
{
edgeAnchor = FindObjectOfType<EdgeAnchor>();
if (edgeAnchor == null)
{
Debug.LogWarning("[PlayerController] No EdgeAnchor found in scene. Origin Y position won't update with camera changes.");
}
else
{
Debug.Log($"[PlayerController] Auto-connected to EdgeAnchor on {edgeAnchor.gameObject.name}");
}
}
}
// Subscribe to edge anchor events if it exists
if (edgeAnchor != null)
{
// Unsubscribe first to prevent duplicate subscriptions
edgeAnchor.OnPositionUpdated -= UpdateOriginYFromAnchor;
edgeAnchor.OnPositionUpdated += UpdateOriginYFromAnchor;
// Update origin Y based on current anchor position
UpdateOriginYFromAnchor();
}
DivingGameManager.Instance.OnGameInitialized += Initialize;
// If game is already initialized, initialize immediately
@@ -70,6 +107,12 @@ namespace Minigames.DivingForPictures
private void OnDestroy()
{
DivingGameManager.Instance.OnGameInitialized -= Initialize;
// Unsubscribe from edge anchor events
if (edgeAnchor != null)
{
edgeAnchor.OnPositionUpdated -= UpdateOriginYFromAnchor;
}
}
/// <summary>
@@ -185,5 +228,31 @@ namespace Minigames.DivingForPictures
}
transform.position = new Vector3(newX, newY, transform.position.z);
}
/// <summary>
/// Updates the origin Y position based on camera adjustments
/// </summary>
public void UpdateOriginY(float newOriginY)
{
_originY = newOriginY;
}
/// <summary>
/// Updates the origin Y position based on the current position of the player
/// This method is intended to be called by the camera adapter when the camera is adjusted.
/// </summary>
private void UpdateOriginYFromCurrentPosition()
{
_originY = transform.position.y;
}
/// <summary>
/// Updates the origin Y position based on the current position of the edge anchor
/// This method is intended to be called by the edge anchor when its position is updated.
/// </summary>
private void UpdateOriginYFromAnchor()
{
_originY = edgeAnchor.transform.position.y;
}
}
}

View File

@@ -16,12 +16,43 @@ public class RockFollower : MonoBehaviour
/// </summary>
public bool useWobbleOffset = true;
/// <summary>
/// The base Y position for the rock.
/// The vertical distance between the rock and the bottle.
/// </summary>
public float baseY = -6f;
[SerializeField] private float verticalDistance = 6f;
private float velocityX; // For SmoothDamp
#if UNITY_EDITOR
/// <summary>
/// Called in editor when properties are changed.
/// Updates the object's position when verticalDistance is modified.
/// </summary>
private void OnValidate()
{
// Only update position if playing or in prefab mode
if (Application.isPlaying || UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this))
return;
if (bottleTransform != null)
{
// Calculate the new Y position based on bottle's position and the updated verticalDistance
float newY = bottleTransform.position.y - verticalDistance;
// Apply the wobble offset if enabled
if (useWobbleOffset && bottleWobble != null)
{
newY += bottleWobble.VerticalOffset;
}
// Update only the Y position, keeping X and Z unchanged
transform.position = new Vector3(transform.position.x, newY, transform.position.z);
// Mark the scene as dirty to ensure changes are saved
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEngine.SceneManagement.SceneManager.GetActiveScene());
}
}
#endif
void Update()
{
if (bottleTransform == null) return;
@@ -33,8 +64,8 @@ public class RockFollower : MonoBehaviour
// Smoothly follow bottle's X with stiffer motion
float newX = Mathf.SmoothDamp(currentX, targetX, ref velocityX, 1f / followStiffness);
// Calculate Y position
float newY = baseY;
// Calculate Y position based on bottle's position and vertical distance
float newY = bottleTransform.position.y - verticalDistance;
if (useWobbleOffset && bottleWobble != null)
{
newY += bottleWobble.VerticalOffset;