using System; using System.Collections; using Core; using Core.Settings; using UnityEngine; using Utils; using Utils.UI; namespace Minigames.DivingForPictures.Screenshot { /// /// Singleton manager for diving minigame screenshot functionality. /// Provides easy-to-use TakeScreenshot() and TakeScreenshotAsync() methods. /// Integrates with PhotoManager for disk storage and ScreenshotFlyawayAnimation for visual feedback. /// public class DivingScreenshotManager : MonoBehaviour { private static DivingScreenshotManager _instance; public static DivingScreenshotManager Instance { get { if (_instance == null && Application.isPlaying) { _instance = FindAnyObjectByType(); if (_instance == null) { GameObject go = new GameObject("DivingScreenshotManager"); _instance = go.AddComponent(); } } return _instance; } } [Header("Screenshot Settings")] [SerializeField] private GameObject[] _uiElementsToHide; [Header("Flash Effect")] [SerializeField] private GameObject _flashEffect; // State tracking private int _screenshotCount; private int _playerScore; private bool _isCapturing; // Settings reference private IDivingMinigameSettings _settings; // Public properties public int ScreenshotCount => _screenshotCount; public int PlayerScore => _playerScore; public bool IsCapturing => _isCapturing; // Events public event Action OnScreenshotCountChanged; public event Action OnScoreChanged; public event Action OnScreenshotCaptured; // photoId, texture private void Awake() { if (_instance == null) { _instance = this; } else if (_instance != this) { Destroy(gameObject); return; } } private void Start() { _settings = GameManager.GetSettingsObject(); } /// /// Take a screenshot using coroutine. Simple synchronous call. /// /// Optional monster reference for score calculation /// Optional proximity score (0-1) public void TakeScreenshot(Monster.Monster monster = null, float proximity = 0f) { if (_isCapturing) { Logging.Warning("[DivingScreenshotManager] Already capturing a screenshot!"); return; } StartCoroutine(TakeScreenshotCoroutine(monster, proximity)); } /// /// Take a screenshot asynchronously. Returns when capture is complete. /// /// Optional monster reference for score calculation /// Optional proximity score (0-1) public Coroutine TakeScreenshotAsync(Monster.Monster monster = null, float proximity = 0f) { if (_isCapturing) { Logging.Warning("[DivingScreenshotManager] Already capturing a screenshot!"); return null; } return StartCoroutine(TakeScreenshotCoroutine(monster, proximity)); } /// /// Internal coroutine that handles the screenshot capture process /// private IEnumerator TakeScreenshotCoroutine(Monster.Monster monster, float proximity) { _isCapturing = true; // Get viewfinder and validate references var viewfinderManager = PictureCamera.CameraViewfinderManager.Instance; if (viewfinderManager == null || viewfinderManager.CurrentViewfinder == null) { Logging.Error("[DivingScreenshotManager] No active viewfinder found!"); _isCapturing = false; yield break; } var viewfinder = viewfinderManager.CurrentViewfinder; RectTransform captureArea = viewfinder?.CaptureArea; if (captureArea == null) { Logging.Error($"[DivingScreenshotManager] Capture area not configured! Viewfinder: {viewfinder?.gameObject.name}"); _isCapturing = false; yield break; } // Show flash effect if (_flashEffect != null) { _flashEffect.SetActive(true); yield return new WaitForSeconds(0.1f); _flashEffect.SetActive(false); } // Combine global UI elements with viewfinder-specific ones GameObject[] combinedUIToHide = CombineUIElementsToHide(_uiElementsToHide, viewfinder.UIElementsToHideDuringCapture); // Capture and save using PhotoManager bool captureSuccess = false; string savedPhotoId = null; Texture2D capturedTexture = null; yield return PhotoManager.CaptureAndSaveCoroutine( CaptureType.DivingMinigame, captureArea, combinedUIToHide, onSuccess: (photoId) => { savedPhotoId = photoId; captureSuccess = true; // Load the texture back for animation capturedTexture = PhotoManager.LoadPhoto(CaptureType.DivingMinigame, photoId); Logging.Debug($"[DivingScreenshotManager] Screenshot saved: {photoId}"); }, onFailure: (error) => { Logging.Error($"[DivingScreenshotManager] Screenshot failed: {error}"); captureSuccess = false; } ); if (!captureSuccess) { _isCapturing = false; yield break; } // Calculate score int earnedScore = CalculateScore(monster, proximity); _playerScore += earnedScore; _screenshotCount++; // Fire events OnScreenshotCountChanged?.Invoke(_screenshotCount); OnScoreChanged?.Invoke(_screenshotCount); // Pass screenshot count for UI compatibility OnScreenshotCaptured?.Invoke(savedPhotoId, capturedTexture); Logging.Debug($"[DivingScreenshotManager] Score: +{earnedScore} (Total: {_playerScore}, Count: {_screenshotCount})"); // Trigger flyaway animation with target from DivingScoreUI if (capturedTexture != null && viewfinder.FlyawayAnimation != null) { Transform photoIconTarget = DivingScoreUI.Instance?.PhotoIconTarget; viewfinder.FlyawayAnimation.PlayAnimation(capturedTexture, photoIconTarget); } _isCapturing = false; } /// /// Calculate score based on monster depth and proximity /// private int CalculateScore(Monster.Monster monster, float proximity) { if (_settings == null) { return 100; // Default fallback } int baseScore = _settings.BasePoints; // Add depth bonus if monster reference provided if (monster != null) { int depthBonus = Mathf.FloorToInt(Mathf.Abs(monster.transform.position.y) * _settings.DepthMultiplier); baseScore += depthBonus; } // Add proximity bonus (0-1 scale, multiply by some factor) int proximityBonus = Mathf.RoundToInt(proximity * 50f); baseScore += proximityBonus; return baseScore; } /// /// Get booster pack count based on screenshot count (for end game reward) /// public int CalculateBoosterPackReward() { if (_screenshotCount <= 3) { return 1; } else if (_screenshotCount <= 5) { return 2; } else if (_screenshotCount <= 10) { return 3; } else { return 4; } } /// /// Reset state for new game /// public void ResetState() { _screenshotCount = 0; _playerScore = 0; _isCapturing = false; } /// /// Combines global UI elements with viewfinder-specific UI elements /// private GameObject[] CombineUIElementsToHide(GameObject[] globalElements, GameObject[] viewfinderElements) { if (globalElements == null && viewfinderElements == null) return null; if (globalElements == null) return viewfinderElements; if (viewfinderElements == null) return globalElements; // Combine both arrays GameObject[] combined = new GameObject[globalElements.Length + viewfinderElements.Length]; globalElements.CopyTo(combined, 0); viewfinderElements.CopyTo(combined, globalElements.Length); return combined; } } }