First steps with camera framing
This commit is contained in:
3
Assets/Scripts/AppleHillsCamera.meta
Normal file
3
Assets/Scripts/AppleHillsCamera.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95f834c9cbc34cff9490c5582d66e463
|
||||
timeCreated: 1760359480
|
||||
111
Assets/Scripts/AppleHillsCamera/CameraScreenAdapter.cs
Normal file
111
Assets/Scripts/AppleHillsCamera/CameraScreenAdapter.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using UnityEngine;
|
||||
using Unity.Cinemachine;
|
||||
|
||||
namespace AppleHillsCamera
|
||||
{
|
||||
/// <summary>
|
||||
/// Adjusts the camera's orthographic size to match the target width from a ScreenReferenceMarker.
|
||||
/// Works with both regular cameras and Cinemachine virtual cameras.
|
||||
/// </summary>
|
||||
public class CameraScreenAdapter : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Reference that defines the target width to match")]
|
||||
public ScreenReferenceMarker referenceMarker;
|
||||
|
||||
[Tooltip("Whether to adjust the camera automatically on Start")]
|
||||
public bool adjustOnStart = true;
|
||||
|
||||
[Tooltip("Whether to adjust the camera automatically when the screen size changes")]
|
||||
public bool adjustOnScreenResize = true;
|
||||
|
||||
private Camera _regularCamera;
|
||||
private CinemachineCamera _virtualCamera;
|
||||
private int _lastScreenWidth;
|
||||
private int _lastScreenHeight;
|
||||
private bool _usingCinemachine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Try to get regular camera first
|
||||
_regularCamera = GetComponent<Camera>();
|
||||
|
||||
// Try to get Cinemachine camera if no regular camera or if both exist
|
||||
_virtualCamera = GetComponent<CinemachineCamera>();
|
||||
|
||||
// Determine which camera type we're using
|
||||
_usingCinemachine = _virtualCamera != null;
|
||||
|
||||
_lastScreenWidth = Screen.width;
|
||||
_lastScreenHeight = Screen.height;
|
||||
|
||||
if (!_usingCinemachine && _regularCamera == null)
|
||||
{
|
||||
Debug.LogError("CameraScreenAdapter: No camera component found. Add this script to a GameObject with either Camera or CinemachineCamera component.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (adjustOnStart)
|
||||
{
|
||||
AdjustCamera();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (adjustOnScreenResize &&
|
||||
(Screen.width != _lastScreenWidth || Screen.height != _lastScreenHeight))
|
||||
{
|
||||
AdjustCamera();
|
||||
_lastScreenWidth = Screen.width;
|
||||
_lastScreenHeight = Screen.height;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually trigger camera adjustment to match the reference width.
|
||||
/// </summary>
|
||||
public void AdjustCamera()
|
||||
{
|
||||
if (referenceMarker == null)
|
||||
{
|
||||
Debug.LogWarning("CameraScreenAdapter: Missing reference marker.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)
|
||||
float orthoSize = (targetWidth / 2f) * screenAspect;
|
||||
|
||||
// Apply the calculated size to the camera
|
||||
if (_usingCinemachine)
|
||||
{
|
||||
// Apply to Cinemachine virtual camera
|
||||
var lens = _virtualCamera.Lens;
|
||||
lens.OrthographicSize = orthoSize;
|
||||
_virtualCamera.Lens = lens;
|
||||
Debug.Log($"Cinemachine Camera adapted: Width={targetWidth}, Aspect={screenAspect:F2}, OrthoSize={orthoSize:F2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply to regular camera
|
||||
if (_regularCamera.orthographic)
|
||||
{
|
||||
_regularCamera.orthographicSize = orthoSize;
|
||||
Debug.Log($"Camera adapted: Width={targetWidth}, Aspect={screenAspect:F2}, OrthoSize={orthoSize:F2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("CameraScreenAdapter: Regular camera is not in orthographic mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a71a21143bd4f4992d08829084d1e3b
|
||||
timeCreated: 1760359498
|
||||
310
Assets/Scripts/AppleHillsCamera/EdgeAnchor.cs
Normal file
310
Assets/Scripts/AppleHillsCamera/EdgeAnchor.cs
Normal file
@@ -0,0 +1,310 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHillsCamera
|
||||
{
|
||||
/// <summary>
|
||||
/// Anchors a game object at a fixed distance from a screen edge.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode] // Make it run in the editor
|
||||
public class EdgeAnchor : MonoBehaviour
|
||||
{
|
||||
public enum AnchorEdge
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
[Tooltip("Reference marker that defines the screen edges and margins")]
|
||||
public ScreenReferenceMarker referenceMarker;
|
||||
|
||||
[Tooltip("Which screen edge to anchor to")]
|
||||
public AnchorEdge anchorEdge = AnchorEdge.Top;
|
||||
|
||||
[Tooltip("Whether to use the predefined margin from the reference marker")]
|
||||
public bool useReferenceMargin = true;
|
||||
|
||||
[Tooltip("Custom margin to use if not using the reference margin")]
|
||||
public float customMargin = 1f;
|
||||
|
||||
[Tooltip("Whether to adjust the position automatically on Start")]
|
||||
public bool adjustOnStart = true;
|
||||
|
||||
[Tooltip("Whether to adjust the position when the screen size changes")]
|
||||
public bool adjustOnScreenResize = true;
|
||||
|
||||
[Tooltip("Whether to preserve the object's position on other axes")]
|
||||
public bool preserveOtherAxes = 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);
|
||||
|
||||
private Camera _camera;
|
||||
private int _lastScreenWidth;
|
||||
private int _lastScreenHeight;
|
||||
private Vector3 _originalPosition;
|
||||
private bool _initialized = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (!showVisualization || referenceMarker == null)
|
||||
return;
|
||||
|
||||
// Draw a line from the object to its anchor point
|
||||
Vector3 anchorPoint = GetAnchorPoint();
|
||||
|
||||
// Save original color
|
||||
Color originalColor = Gizmos.color;
|
||||
|
||||
// Draw line to anchor point
|
||||
Gizmos.color = visualizationColor;
|
||||
Gizmos.DrawLine(gameObject.transform.position, anchorPoint);
|
||||
|
||||
// Draw a small sphere at the anchor point
|
||||
Gizmos.DrawSphere(anchorPoint, 0.1f);
|
||||
|
||||
// Restore original color
|
||||
Gizmos.color = originalColor;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_originalPosition = transform.position;
|
||||
FindCamera();
|
||||
_lastScreenWidth = Screen.width;
|
||||
_lastScreenHeight = Screen.height;
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
_originalPosition = transform.position;
|
||||
FindCamera();
|
||||
_lastScreenWidth = Screen.width;
|
||||
_lastScreenHeight = Screen.height;
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
// Adjust position immediately when enabled in editor
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UpdatePosition();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (adjustOnStart && Application.isPlaying)
|
||||
{
|
||||
UpdatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
bool shouldUpdate = false;
|
||||
|
||||
// Update if screen size has changed
|
||||
if (adjustOnScreenResize &&
|
||||
(Screen.width != _lastScreenWidth || Screen.height != _lastScreenHeight))
|
||||
{
|
||||
shouldUpdate = true;
|
||||
_lastScreenWidth = Screen.width;
|
||||
_lastScreenHeight = Screen.height;
|
||||
}
|
||||
|
||||
// In editor, check for reference marker changes or inspector changes
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
shouldUpdate = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update position if needed
|
||||
if (shouldUpdate)
|
||||
{
|
||||
UpdatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void FindCamera()
|
||||
{
|
||||
// Look for the main camera
|
||||
_camera = Camera.main;
|
||||
|
||||
// If no main camera found, try to find any camera
|
||||
if (_camera == null)
|
||||
{
|
||||
_camera = FindAnyObjectByType<Camera>();
|
||||
}
|
||||
|
||||
if (_camera == null)
|
||||
{
|
||||
Debug.LogError("EdgeAnchor: No camera found in the scene.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually trigger position adjustment based on the anchor settings.
|
||||
/// </summary>
|
||||
public void UpdatePosition()
|
||||
{
|
||||
if (referenceMarker == null)
|
||||
{
|
||||
Debug.LogWarning("EdgeAnchor: Missing reference marker.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_camera == null)
|
||||
{
|
||||
FindCamera();
|
||||
if (_camera == null) return;
|
||||
}
|
||||
|
||||
// Get the margin value to use
|
||||
float margin = GetMarginValue();
|
||||
|
||||
// Calculate the new position based on anchor edge
|
||||
Vector3 newPosition = CalculateAnchoredPosition(margin);
|
||||
|
||||
// If preserving other axes, keep their original values
|
||||
if (preserveOtherAxes)
|
||||
{
|
||||
switch (anchorEdge)
|
||||
{
|
||||
case AnchorEdge.Top:
|
||||
case AnchorEdge.Bottom:
|
||||
newPosition.x = transform.position.x;
|
||||
newPosition.z = transform.position.z;
|
||||
break;
|
||||
case AnchorEdge.Left:
|
||||
case AnchorEdge.Right:
|
||||
newPosition.y = transform.position.y;
|
||||
newPosition.z = transform.position.z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the new position
|
||||
transform.position = newPosition;
|
||||
}
|
||||
|
||||
private float GetMarginValue()
|
||||
{
|
||||
if (!useReferenceMargin)
|
||||
{
|
||||
return customMargin;
|
||||
}
|
||||
|
||||
switch (anchorEdge)
|
||||
{
|
||||
case AnchorEdge.Top:
|
||||
return referenceMarker.topMargin;
|
||||
case AnchorEdge.Bottom:
|
||||
return referenceMarker.bottomMargin;
|
||||
case AnchorEdge.Left:
|
||||
return referenceMarker.leftMargin;
|
||||
case AnchorEdge.Right:
|
||||
return referenceMarker.rightMargin;
|
||||
default:
|
||||
return customMargin;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 CalculateAnchoredPosition(float margin)
|
||||
{
|
||||
// Get the screen edges in world coordinates
|
||||
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;
|
||||
|
||||
switch (anchorEdge)
|
||||
{
|
||||
case AnchorEdge.Top:
|
||||
// Position from the top of the screen
|
||||
newPosition.y = cameraPosition.y + cameraOrthoSize - margin;
|
||||
break;
|
||||
|
||||
case AnchorEdge.Bottom:
|
||||
// Position from the bottom of the screen
|
||||
newPosition.y = cameraPosition.y - cameraOrthoSize + margin;
|
||||
break;
|
||||
|
||||
case AnchorEdge.Left:
|
||||
// Position from the left of the screen
|
||||
newPosition.x = cameraPosition.x - (screenWidth / 2f) + margin;
|
||||
break;
|
||||
|
||||
case AnchorEdge.Right:
|
||||
// Position from the right of the screen
|
||||
newPosition.x = cameraPosition.x + (screenWidth / 2f) - margin;
|
||||
break;
|
||||
}
|
||||
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the anchor point on the edge for visualization
|
||||
/// </summary>
|
||||
private Vector3 GetAnchorPoint()
|
||||
{
|
||||
if (_camera == null)
|
||||
{
|
||||
FindCamera();
|
||||
if (_camera == null) return transform.position;
|
||||
}
|
||||
|
||||
// Get the screen edges in world coordinates
|
||||
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 anchorPoint = transform.position;
|
||||
|
||||
switch (anchorEdge)
|
||||
{
|
||||
case AnchorEdge.Top:
|
||||
// Anchor at top edge with same X as the object
|
||||
anchorPoint.y = cameraPosition.y + cameraOrthoSize;
|
||||
break;
|
||||
|
||||
case AnchorEdge.Bottom:
|
||||
// Anchor at bottom edge with same X as the object
|
||||
anchorPoint.y = cameraPosition.y - cameraOrthoSize;
|
||||
break;
|
||||
|
||||
case AnchorEdge.Left:
|
||||
// Anchor at left edge with same Y as the object
|
||||
anchorPoint.x = cameraPosition.x - (screenWidth / 2f);
|
||||
break;
|
||||
|
||||
case AnchorEdge.Right:
|
||||
// Anchor at right edge with same Y as the object
|
||||
anchorPoint.x = cameraPosition.x + (screenWidth / 2f);
|
||||
break;
|
||||
}
|
||||
|
||||
return anchorPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/AppleHillsCamera/EdgeAnchor.cs.meta
Normal file
3
Assets/Scripts/AppleHillsCamera/EdgeAnchor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed380d10e1e04ae7990e5c726c929063
|
||||
timeCreated: 1760359522
|
||||
142
Assets/Scripts/AppleHillsCamera/ScreenReferenceMarker.cs
Normal file
142
Assets/Scripts/AppleHillsCamera/ScreenReferenceMarker.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AppleHillsCamera
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines reference sizes and distances for screen adaptation.
|
||||
/// Used by CameraScreenAdapter and EdgeAnchor components.
|
||||
/// </summary>
|
||||
public class ScreenReferenceMarker : MonoBehaviour
|
||||
{
|
||||
[Header("Horizontal Reference")]
|
||||
[Tooltip("The target width that should match the screen width")]
|
||||
public float targetWidth = 10f;
|
||||
|
||||
[Header("Vertical References")]
|
||||
[Tooltip("Distance from top of screen to use for anchoring")]
|
||||
public float topMargin = 1f;
|
||||
|
||||
[Tooltip("Distance from bottom of screen to use for anchoring")]
|
||||
public float bottomMargin = 1f;
|
||||
|
||||
[Tooltip("Distance from left of screen to use for anchoring")]
|
||||
public float leftMargin = 1f;
|
||||
|
||||
[Tooltip("Distance from right of screen to use for anchoring")]
|
||||
public float rightMargin = 1f;
|
||||
|
||||
[Header("Visualization")]
|
||||
[Tooltip("Color to use for gizmo visualization")]
|
||||
public Color gizmoColor = new Color(0f, 1f, 0f, 0.5f);
|
||||
|
||||
[Tooltip("Color to use for screen edge visualization")]
|
||||
public Color screenEdgeColor = new Color(1f, 1f, 0f, 0.3f);
|
||||
|
||||
[Tooltip("Show the vertical margins in scene view")]
|
||||
public bool showVerticalMargins = true;
|
||||
|
||||
[Tooltip("Show the horizontal margins in scene view")]
|
||||
public bool showHorizontalMargins = true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
// Save original color
|
||||
Color originalColor = Gizmos.color;
|
||||
|
||||
// Set the color for our gizmos
|
||||
Gizmos.color = gizmoColor;
|
||||
|
||||
Vector3 position = transform.position;
|
||||
|
||||
// Draw the width reference
|
||||
Vector3 left = position + Vector3.left * (targetWidth / 2f);
|
||||
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;
|
||||
|
||||
// Try to get camera references in the preferred order
|
||||
|
||||
// 1. Try to find the main camera in the scene (highest priority)
|
||||
Camera mainCamera = Camera.main;
|
||||
if (mainCamera != null && mainCamera.orthographic)
|
||||
{
|
||||
// Use the main camera's actual orthographic size for the height
|
||||
halfHeight = mainCamera.orthographicSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2. Use Game/Simulator window resolution
|
||||
float gameViewAspect = (float)Screen.height / Screen.width;
|
||||
halfHeight = halfWidth * gameViewAspect;
|
||||
|
||||
// 3. Fallback to the scene view camera if needed
|
||||
UnityEditor.SceneView sceneView = UnityEditor.SceneView.lastActiveSceneView;
|
||||
if (sceneView != null && sceneView.camera != null && sceneView.camera.orthographic)
|
||||
{
|
||||
// Use the scene view camera's aspect ratio instead
|
||||
float sceneAspect = sceneView.camera.pixelHeight / (float)sceneView.camera.pixelWidth;
|
||||
halfHeight = halfWidth * sceneAspect;
|
||||
}
|
||||
}
|
||||
|
||||
// Screen edge positions
|
||||
Vector3 topEdge = position + Vector3.up * halfHeight;
|
||||
Vector3 bottomEdge = position + Vector3.down * halfHeight;
|
||||
Vector3 leftEdge = position + Vector3.left * halfWidth;
|
||||
Vector3 rightEdge = position + Vector3.right * halfWidth;
|
||||
|
||||
// Draw screen edges with yellow color
|
||||
Gizmos.color = screenEdgeColor;
|
||||
|
||||
// Draw full screen rectangle
|
||||
Gizmos.DrawLine(leftEdge + Vector3.up * halfHeight, rightEdge + Vector3.up * halfHeight); // Top edge
|
||||
Gizmos.DrawLine(leftEdge + Vector3.down * halfHeight, rightEdge + Vector3.down * halfHeight); // Bottom edge
|
||||
Gizmos.DrawLine(leftEdge + Vector3.up * halfHeight, leftEdge + Vector3.down * halfHeight); // Left edge
|
||||
Gizmos.DrawLine(rightEdge + Vector3.up * halfHeight, rightEdge + Vector3.down * halfHeight); // Right edge
|
||||
|
||||
// Draw margin references if enabled
|
||||
Gizmos.color = gizmoColor;
|
||||
|
||||
if (showVerticalMargins)
|
||||
{
|
||||
// Top margin (distance from top edge)
|
||||
Gizmos.DrawLine(
|
||||
topEdge + Vector3.down * topMargin + Vector3.left * (targetWidth / 4f),
|
||||
topEdge + Vector3.down * topMargin + Vector3.right * (targetWidth / 4f));
|
||||
|
||||
// Bottom margin (distance from bottom edge)
|
||||
Gizmos.DrawLine(
|
||||
bottomEdge + Vector3.up * bottomMargin + Vector3.left * (targetWidth / 4f),
|
||||
bottomEdge + Vector3.up * bottomMargin + Vector3.right * (targetWidth / 4f));
|
||||
}
|
||||
|
||||
if (showHorizontalMargins)
|
||||
{
|
||||
// Left margin (distance from left edge)
|
||||
Gizmos.DrawLine(
|
||||
leftEdge + Vector3.right * leftMargin + Vector3.up * (halfHeight / 2f),
|
||||
leftEdge + Vector3.right * leftMargin + Vector3.down * (halfHeight / 2f));
|
||||
|
||||
// Right margin (distance from right edge)
|
||||
Gizmos.DrawLine(
|
||||
rightEdge + Vector3.left * rightMargin + Vector3.up * (halfHeight / 2f),
|
||||
rightEdge + Vector3.left * rightMargin + Vector3.down * (halfHeight / 2f));
|
||||
}
|
||||
|
||||
// Restore original color
|
||||
Gizmos.color = originalColor;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3058fe4801134fea916ad685f924668f
|
||||
timeCreated: 1760359480
|
||||
@@ -1,123 +1,128 @@
|
||||
using System;
|
||||
using AppleHills.Core.Settings;
|
||||
using Core;
|
||||
using Input;
|
||||
using Interactions;
|
||||
using UnityEngine;
|
||||
using AppleHills.Core.Settings;
|
||||
using Core; // Added for IInteractionSettings
|
||||
|
||||
/// <summary>
|
||||
/// Handles level switching when interacted with. Applies switch data and triggers scene transitions.
|
||||
/// </summary>
|
||||
public class LevelSwitch : MonoBehaviour
|
||||
// Added for IInteractionSettings
|
||||
|
||||
namespace LevelS
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for this level switch (target scene, icon, etc).
|
||||
/// Handles level switching when interacted with. Applies switch data and triggers scene transitions.
|
||||
/// </summary>
|
||||
public LevelSwitchData switchData;
|
||||
private SpriteRenderer _iconRenderer;
|
||||
private Interactable _interactable;
|
||||
public class LevelSwitch : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for this level switch (target scene, icon, etc).
|
||||
/// </summary>
|
||||
public LevelSwitchData switchData;
|
||||
private SpriteRenderer _iconRenderer;
|
||||
private Interactable _interactable;
|
||||
|
||||
// Settings reference
|
||||
private IInteractionSettings _interactionSettings;
|
||||
// Settings reference
|
||||
private IInteractionSettings _interactionSettings;
|
||||
|
||||
private bool _isActive = true;
|
||||
private bool _isActive = true;
|
||||
|
||||
/// <summary>
|
||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||
/// </summary>
|
||||
void Awake()
|
||||
{
|
||||
_isActive = true;
|
||||
if (_iconRenderer == null)
|
||||
_iconRenderer = GetComponent<SpriteRenderer>();
|
||||
_interactable = GetComponent<Interactable>();
|
||||
if (_interactable != null)
|
||||
/// <summary>
|
||||
/// Unity Awake callback. Sets up icon, interactable, and event handlers.
|
||||
/// </summary>
|
||||
void Awake()
|
||||
{
|
||||
_interactable.characterArrived.AddListener(OnCharacterArrived);
|
||||
_isActive = true;
|
||||
if (_iconRenderer == null)
|
||||
_iconRenderer = GetComponent<SpriteRenderer>();
|
||||
_interactable = GetComponent<Interactable>();
|
||||
if (_interactable != null)
|
||||
{
|
||||
_interactable.characterArrived.AddListener(OnCharacterArrived);
|
||||
}
|
||||
|
||||
// Initialize settings reference
|
||||
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
||||
|
||||
ApplySwitchData();
|
||||
}
|
||||
|
||||
// Initialize settings reference
|
||||
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
||||
|
||||
ApplySwitchData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity OnDestroy callback. Cleans up event handlers.
|
||||
/// </summary>
|
||||
void OnDestroy()
|
||||
{
|
||||
if (_interactable != null)
|
||||
/// <summary>
|
||||
/// Unity OnDestroy callback. Cleans up event handlers.
|
||||
/// </summary>
|
||||
void OnDestroy()
|
||||
{
|
||||
_interactable.characterArrived.RemoveListener(OnCharacterArrived);
|
||||
if (_interactable != null)
|
||||
{
|
||||
_interactable.characterArrived.RemoveListener(OnCharacterArrived);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Unity OnValidate callback. Ensures icon and data are up to date in editor.
|
||||
/// </summary>
|
||||
void OnValidate()
|
||||
{
|
||||
if (_iconRenderer == null)
|
||||
_iconRenderer = GetComponent<SpriteRenderer>();
|
||||
ApplySwitchData();
|
||||
}
|
||||
/// <summary>
|
||||
/// Unity OnValidate callback. Ensures icon and data are up to date in editor.
|
||||
/// </summary>
|
||||
void OnValidate()
|
||||
{
|
||||
if (_iconRenderer == null)
|
||||
_iconRenderer = GetComponent<SpriteRenderer>();
|
||||
ApplySwitchData();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Applies the switch data to the level switch (icon, name, etc).
|
||||
/// </summary>
|
||||
public void ApplySwitchData()
|
||||
{
|
||||
if (switchData != null)
|
||||
/// <summary>
|
||||
/// Applies the switch data to the level switch (icon, name, etc).
|
||||
/// </summary>
|
||||
public void ApplySwitchData()
|
||||
{
|
||||
if (_iconRenderer != null)
|
||||
_iconRenderer.sprite = switchData.mapSprite;
|
||||
gameObject.name = switchData.targetLevelSceneName;
|
||||
// Optionally update other fields, e.g. description
|
||||
if (switchData != null)
|
||||
{
|
||||
if (_iconRenderer != null)
|
||||
_iconRenderer.sprite = switchData.mapSprite;
|
||||
gameObject.name = switchData.targetLevelSceneName;
|
||||
// Optionally update other fields, e.g. description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the start of an interaction (shows confirmation menu and switches the level if confirmed).
|
||||
/// </summary>
|
||||
private void OnCharacterArrived()
|
||||
{
|
||||
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName) || !_isActive)
|
||||
return;
|
||||
/// <summary>
|
||||
/// Handles the start of an interaction (shows confirmation menu and switches the level if confirmed).
|
||||
/// </summary>
|
||||
private void OnCharacterArrived()
|
||||
{
|
||||
if (switchData == null || string.IsNullOrEmpty(switchData.targetLevelSceneName) || !_isActive)
|
||||
return;
|
||||
|
||||
var menuPrefab = _interactionSettings?.LevelSwitchMenuPrefab;
|
||||
if (menuPrefab == null)
|
||||
{
|
||||
Debug.LogError("LevelSwitchMenu prefab not assigned in InteractionSettings!");
|
||||
return;
|
||||
}
|
||||
// Spawn the menu overlay (assume Canvas parent is handled in prefab setup)
|
||||
var menuGo = Instantiate(menuPrefab);
|
||||
var menu = menuGo.GetComponent<LevelSwitchMenu>();
|
||||
if (menu == null)
|
||||
{
|
||||
Debug.LogError("LevelSwitchMenu component missing on prefab!");
|
||||
Destroy(menuGo);
|
||||
return;
|
||||
}
|
||||
// Setup menu with data and callbacks
|
||||
menu.Setup(switchData, OnMenuConfirm, OnMenuCancel);
|
||||
_isActive = false; // Prevent re-triggering until menu is closed
|
||||
var menuPrefab = _interactionSettings?.LevelSwitchMenuPrefab;
|
||||
if (menuPrefab == null)
|
||||
{
|
||||
Debug.LogError("LevelSwitchMenu prefab not assigned in InteractionSettings!");
|
||||
return;
|
||||
}
|
||||
// Spawn the menu overlay (assume Canvas parent is handled in prefab setup)
|
||||
var menuGo = Instantiate(menuPrefab);
|
||||
var menu = menuGo.GetComponent<LevelSwitchMenu>();
|
||||
if (menu == null)
|
||||
{
|
||||
Debug.LogError("LevelSwitchMenu component missing on prefab!");
|
||||
Destroy(menuGo);
|
||||
return;
|
||||
}
|
||||
// Setup menu with data and callbacks
|
||||
menu.Setup(switchData, OnMenuConfirm, OnMenuCancel);
|
||||
_isActive = false; // Prevent re-triggering until menu is closed
|
||||
|
||||
// Switch input mode to UI only
|
||||
InputManager.Instance.SetInputMode(InputMode.UI);
|
||||
}
|
||||
// Switch input mode to UI only
|
||||
InputManager.Instance.SetInputMode(InputMode.UI);
|
||||
}
|
||||
|
||||
private async void OnMenuConfirm()
|
||||
{
|
||||
var progress = new Progress<float>(p => Debug.Log($"Loading progress: {p * 100:F0}%"));
|
||||
await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress);
|
||||
}
|
||||
private async void OnMenuConfirm()
|
||||
{
|
||||
var progress = new Progress<float>(p => Debug.Log($"Loading progress: {p * 100:F0}%"));
|
||||
await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress);
|
||||
}
|
||||
|
||||
private void OnMenuCancel()
|
||||
{
|
||||
_isActive = true; // Allow interaction again if cancelled
|
||||
private void OnMenuCancel()
|
||||
{
|
||||
_isActive = true; // Allow interaction again if cancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user