Update the rotation enforcement to automatically lock device into

desired orientation.
This commit is contained in:
Michal Pikulski
2025-10-24 16:26:23 +02:00
parent 5a85a602bd
commit cc797f09ef
3 changed files with 113 additions and 210 deletions

View File

@@ -1,46 +1,37 @@
using UnityEngine; using System;
using UnityEngine.SceneManagement; using System.Collections;
using System; using Bootstrap;
using Input; using Input;
using Settings; using Settings;
using System.Collections; using UnityEngine;
using Minigames.DivingForPictures; using UnityEngine.SceneManagement;
using Bootstrap;
using Core;
namespace Utility namespace Core
{ {
public class SceneOrientationEnforcer : MonoBehaviour public class SceneOrientationEnforcer : MonoBehaviour
{ {
// Singleton instance
private static SceneOrientationEnforcer _instance; private static SceneOrientationEnforcer _instance;
private static bool _isQuitting;
/// <summary>
/// Singleton instance of the SceneOrientationEnforcer. No longer creates an instance if one doesn't exist.
/// </summary>
public static SceneOrientationEnforcer Instance => _instance; public static SceneOrientationEnforcer Instance => _instance;
[Header("Config")] [Header("Config")]
public SceneOrientationConfig orientationConfig; public SceneOrientationConfig orientationConfig;
public GameObject orientationPromptPrefab; public GameObject orientationPromptPrefab;
public event Action OnOrientationCorrect;
public event Action OnOrientationIncorrect;
private GameObject _promptInstance;
private ScreenOrientationRequirement _requiredOrientation;
private bool _orientationCorrect;
private Coroutine _orientationCheckCoroutine;
private bool _isDivingMinigame = false;
private Coroutine _continuousOrientationCheckCoroutine;
void Awake() void Awake()
{ {
_instance = this; _instance = this;
OnOrientationCorrect += HandleOrientationCorrect;
// Register for post-boot initialization // Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot); BootCompletionService.RegisterInitAction(InitializePostBoot);
#if UNITY_EDITOR
// When playing in the editor, manually invoke OnSceneLoaded for the currently active scene
if (Application.isPlaying)
{
OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single);
}
#endif
} }
private void InitializePostBoot() private void InitializePostBoot()
@@ -50,180 +41,118 @@ namespace Utility
// Subscribe to sceneLoaded event // Subscribe to sceneLoaded event
SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneLoaded += OnSceneLoaded;
// Manually invoke for the first scene (unless it's Main Menu)
var activeScene = SceneManager.GetActiveScene();
if (!IsMainMenuScene(activeScene))
{
OnSceneLoaded(activeScene, LoadSceneMode.Single);
}
} }
/// <summary>
/// Checks if the current device orientation matches the required orientation for the scene
/// </summary>
/// <returns>True if the orientation is correct, false otherwise</returns>
public bool IsOrientationCorrect()
{
switch (_requiredOrientation)
{
case ScreenOrientationRequirement.Portrait:
return Screen.orientation == ScreenOrientation.Portrait || Screen.orientation == ScreenOrientation.PortraitUpsideDown;
case ScreenOrientationRequirement.Landscape:
return Screen.orientation == ScreenOrientation.LandscapeLeft || Screen.orientation == ScreenOrientation.LandscapeRight;
case ScreenOrientationRequirement.NotApplicable:
return true;
default:
return true;
}
}
/// <summary>
/// Checks if the current scene is the diving minigame scene
/// </summary>
/// <returns>True if the scene is "DivingForPictures", false otherwise</returns>
public bool IsDivingMinigameScene(Scene scene)
{
return scene.name == "DivingForPictures";
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode) private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{ {
// Clean up any previous prompt/coroutine // Determine desired orientation for this scene
CleanupPromptAndCoroutine(); string sceneName = scene.name;
ScreenOrientationRequirement requirement = ScreenOrientationRequirement.NotApplicable;
if (IsMainMenuScene(scene)) if (sceneName.ToLower().Contains("bootstrap"))
return;
_isDivingMinigame = IsDivingMinigameScene(scene);
_requiredOrientation = orientationConfig != null ? orientationConfig.GetRequirementForScene(scene.name) : ScreenOrientationRequirement.NotApplicable;
_orientationCorrect = IsOrientationCorrect();
if (!_orientationCorrect)
{ {
InputManager.Instance.SetInputMode(InputMode.UI); // Bootstrap being loaded additively, don't do anything
ShowPrompt(); Logging.Debug($"[SceneOrientationEnforcer] Detected bootstrapped scene: '{sceneName}'. Skipping orientation enforcement.");
// If this is the diving minigame, start continuous orientation checking return;
if (_isDivingMinigame) }
{
_continuousOrientationCheckCoroutine = StartCoroutine(ContinuousOrientationCheckRoutine()); if (orientationConfig != null)
} {
else requirement = orientationConfig.GetRequirementForScene(sceneName);
{
_orientationCheckCoroutine = StartCoroutine(OrientationCheckRoutine());
}
} }
else else
{ {
_orientationCorrect = true; Logging.Debug($"[SceneOrientationEnforcer] No orientationConfig assigned. Defaulting to Landscape for scene '{sceneName}'");
OnOrientationCorrect?.Invoke(); }
// If this is the diving minigame, start continuous orientation checking switch (requirement)
if (_isDivingMinigame) {
{ case ScreenOrientationRequirement.Portrait:
_continuousOrientationCheckCoroutine = StartCoroutine(ContinuousOrientationCheckRoutine()); Logging.Debug($"[SceneOrientationEnforcer] Forcing Portrait for scene '{sceneName}'");
} StartCoroutine(ForcePortrait());
break;
case ScreenOrientationRequirement.Landscape:
Logging.Debug($"[SceneOrientationEnforcer] Forcing Landscape for scene '{sceneName}'");
StartCoroutine(ForceLandscape());
break;
case ScreenOrientationRequirement.NotApplicable:
default:
// Default to landscape when no specific requirement is found
Logging.Debug($"[SceneOrientationEnforcer] No specific orientation for scene '{sceneName}'. Defaulting to Landscape");
StartCoroutine(ForceLandscape());
break;
} }
} }
private System.Collections.IEnumerator OrientationCheckRoutine()
{
while (!IsOrientationCorrect())
{
yield return new WaitForSeconds(0.5f);
}
_orientationCorrect = true;
OnOrientationCorrect?.Invoke();
}
private System.Collections.IEnumerator ContinuousOrientationCheckRoutine()
{
while (!IsOrientationCorrect())
{
yield return new WaitForSeconds(0.5f);
}
_orientationCorrect = true;
OnOrientationCorrect?.Invoke();
while (true)
{
// Wait for a short interval before checking again
yield return new WaitForSeconds(0.2f);
// Check if orientation is now incorrect
if (!IsOrientationCorrect())
{
OnOrientationIncorrect?.Invoke();;
InputManager.Instance.SetInputMode(InputMode.UI);
ShowPrompt();
_continuousOrientationCheckCoroutine = StartCoroutine(ContinuousOrientationCheckRoutine());
yield break; // Exit this coroutine
}
}
}
private void ShowPrompt()
{
if (orientationPromptPrefab != null && _promptInstance == null)
{
_promptInstance = Instantiate(orientationPromptPrefab);
DontDestroyOnLoad(_promptInstance);
}
}
private void HandleOrientationCorrect()
{
if (_promptInstance != null)
{
Destroy(_promptInstance);
_promptInstance = null;
}
if (_orientationCheckCoroutine != null)
{
StopCoroutine(_orientationCheckCoroutine);
_orientationCheckCoroutine = null;
}
InputManager.Instance.SetInputMode(InputMode.GameAndUI);
}
private void CleanupPromptAndCoroutine()
{
if (_promptInstance != null)
{
Destroy(_promptInstance);
_promptInstance = null;
}
if (_orientationCheckCoroutine != null)
{
StopCoroutine(_orientationCheckCoroutine);
_orientationCheckCoroutine = null;
}
if (_continuousOrientationCheckCoroutine != null)
{
StopCoroutine(_continuousOrientationCheckCoroutine);
_continuousOrientationCheckCoroutine = null;
}
}
private bool IsMainMenuScene(Scene scene)
{
// Adjust this logic if you have a different main menu scene name
return scene.name == "Main Menu" || scene.name == "MainMenu";
}
void OnDestroy() void OnDestroy()
{ {
SceneManager.sceneLoaded -= OnSceneLoaded; SceneManager.sceneLoaded -= OnSceneLoaded;
OnOrientationCorrect -= HandleOrientationCorrect; }
CleanupPromptAndCoroutine();
/// <summary>
/// Forces the game into landscape mode, allowing both LandscapeLeft and LandscapeRight.
/// </summary>
public static IEnumerator ForceLandscape()
{
// If we're already in a landscape orientation, nothing to do.
bool currentlyLandscape = Screen.orientation == ScreenOrientation.LandscapeLeft
|| Screen.orientation == ScreenOrientation.LandscapeRight;
if (!currentlyLandscape)
{
// Lock it to portrait and allow the device to orient itself
Logging.Debug($"[SceneOrientationEnforcer] Actually forcing Portrait from previous: {Screen.orientation}");
Screen.orientation = ScreenOrientation.LandscapeRight;
}
else
{
Logging.Debug($"[SceneOrientationEnforcer] Skipping Landscape enforcement, device already in: {Screen.orientation}");
}
yield return null;
// Enable only landscape autorotations
Screen.autorotateToPortrait = false;
Screen.autorotateToPortraitUpsideDown = false;
Screen.autorotateToLandscapeLeft = true;
Screen.autorotateToLandscapeRight = true;
yield return null;
// Allow device to auto-rotate to correct landscape orientation
Screen.orientation = ScreenOrientation.AutoRotation;
} }
void OnApplicationQuit() /// <summary>
/// Forces the game into portrait mode, allowing both Portrait and PortraitUpsideDown.
/// </summary>
public static IEnumerator ForcePortrait()
{ {
_isQuitting = true; // If we're already in a portrait orientation, nothing to do.
bool currentlyPortrait = Screen.orientation == ScreenOrientation.Portrait
|| Screen.orientation == ScreenOrientation.PortraitUpsideDown;
if (!currentlyPortrait)
{
// Lock it to portrait and allow the device to orient itself
Logging.Debug($"[SceneOrientationEnforcer] Actually forcing Portrait from previous: {Screen.orientation}");
Screen.orientation = ScreenOrientation.PortraitUpsideDown;
}
else
{
Logging.Debug($"[SceneOrientationEnforcer] Skipping Portrait enforcement, device already in: {Screen.orientation}");
}
yield return null;
// Enable only portrait autorotations
Screen.autorotateToPortrait = true;
Screen.autorotateToPortraitUpsideDown = true;
Screen.autorotateToLandscapeLeft = false;
Screen.autorotateToLandscapeRight = false;
yield return null;
// Allow device to auto-rotate to correct portrait orientation
Screen.orientation = ScreenOrientation.AutoRotation;
} }
} }
} }

View File

@@ -13,7 +13,6 @@ using UI.Core;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
using UnityEngine.Playables; using UnityEngine.Playables;
using Utility;
namespace Minigames.DivingForPictures namespace Minigames.DivingForPictures
{ {
@@ -169,26 +168,7 @@ namespace Minigames.DivingForPictures
GameManager.Instance.RegisterPausableComponent(this); GameManager.Instance.RegisterPausableComponent(this);
} }
// Subscribe to SceneOrientationEnforcer's event InitializeGame();
if (SceneOrientationEnforcer.Instance != null)
{
// TODO: This is a bit of a hack to make sure the game is initialized after the orientation is correct
SceneOrientationEnforcer.Instance.OnOrientationCorrect += InitializeGame;
SceneOrientationEnforcer.Instance.OnOrientationIncorrect += Pause;
// If orientation is already correct, initialize right away
// This prevents issues if the orientation was already correct before subscription
if (SceneOrientationEnforcer.Instance.IsOrientationCorrect())
{
InitializeGame();
}
}
else
{
Logging.Warning("[DivingGameManager] SceneOrientationEnforcer not found. Initializing game immediately.");
InitializeGame();
}
CinematicsManager.Instance.OnCinematicStopped += EndGame; CinematicsManager.Instance.OnCinematicStopped += EndGame;
} }
@@ -197,12 +177,6 @@ namespace Minigames.DivingForPictures
// Unsubscribe from events when the manager is destroyed // Unsubscribe from events when the manager is destroyed
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken; PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
if (SceneOrientationEnforcer.Instance != null)
{
SceneOrientationEnforcer.Instance.OnOrientationCorrect -= InitializeGame;
SceneOrientationEnforcer.Instance.OnOrientationIncorrect -= Pause;
}
// Unregister from GameManager // Unregister from GameManager
if (GameManager.Instance != null) if (GameManager.Instance != null)
{ {

View File

@@ -8,7 +8,7 @@ PlayerSettings:
AndroidProfiler: 0 AndroidProfiler: 0
AndroidFilterTouchesWhenObscured: 0 AndroidFilterTouchesWhenObscured: 0
AndroidEnableSustainedPerformanceMode: 0 AndroidEnableSustainedPerformanceMode: 0
defaultScreenOrientation: 4 defaultScreenOrientation: 2
targetDevice: 2 targetDevice: 2
useOnDemandResources: 0 useOnDemandResources: 0
accelerometerFrequency: 60 accelerometerFrequency: 60