Files
AppleHillsProduction/Assets/Scripts/Minigames/DivingForPictures/Screenshot/DivingScreenshotManager.cs

287 lines
10 KiB
C#
Raw Normal View History

2025-12-18 10:52:12 +01:00
using System;
using System.Collections;
using Core;
using Core.Settings;
using UnityEngine;
using Utils;
using Utils.UI;
namespace Minigames.DivingForPictures.Screenshot
{
/// <summary>
/// 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.
/// </summary>
public class DivingScreenshotManager : MonoBehaviour
{
private static DivingScreenshotManager _instance;
public static DivingScreenshotManager Instance
{
get
{
if (_instance == null && Application.isPlaying)
{
_instance = FindAnyObjectByType<DivingScreenshotManager>();
if (_instance == null)
{
GameObject go = new GameObject("DivingScreenshotManager");
_instance = go.AddComponent<DivingScreenshotManager>();
}
}
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<int> OnScreenshotCountChanged;
public event Action<int> OnScoreChanged;
public event Action<string, Texture2D> OnScreenshotCaptured; // photoId, texture
private void Awake()
{
if (_instance == null)
{
_instance = this;
}
else if (_instance != this)
{
Destroy(gameObject);
return;
}
}
private void Start()
{
_settings = GameManager.GetSettingsObject<IDivingMinigameSettings>();
}
/// <summary>
/// Take a screenshot using coroutine. Simple synchronous call.
/// </summary>
/// <param name="monster">Optional monster reference for score calculation</param>
/// <param name="proximity">Optional proximity score (0-1)</param>
public void TakeScreenshot(Monster.Monster monster = null, float proximity = 0f)
{
if (_isCapturing)
{
Logging.Warning("[DivingScreenshotManager] Already capturing a screenshot!");
return;
}
StartCoroutine(TakeScreenshotCoroutine(monster, proximity));
}
/// <summary>
/// Take a screenshot asynchronously. Returns when capture is complete.
/// </summary>
/// <param name="monster">Optional monster reference for score calculation</param>
/// <param name="proximity">Optional proximity score (0-1)</param>
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));
}
/// <summary>
/// Internal coroutine that handles the screenshot capture process
/// </summary>
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;
}
/// <summary>
/// Calculate score based on monster depth and proximity
/// </summary>
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;
}
/// <summary>
/// Get booster pack count based on screenshot count (for end game reward)
/// </summary>
public int CalculateBoosterPackReward()
{
if (_screenshotCount <= 3)
{
return 1;
}
else if (_screenshotCount <= 5)
{
return 2;
}
else if (_screenshotCount <= 10)
{
return 3;
}
else
{
return 4;
}
}
/// <summary>
/// Reset state for new game
/// </summary>
public void ResetState()
{
_screenshotCount = 0;
_playerScore = 0;
_isCapturing = false;
}
/// <summary>
/// Combines global UI elements with viewfinder-specific UI elements
/// </summary>
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;
}
}
}