Add skip functionality to Cinematics Manager
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
using Bootstrap;
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace CinematicsM
|
||||
namespace Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles loading, playing and unloading cinematics
|
||||
@@ -20,6 +18,10 @@ namespace CinematicsM
|
||||
private Image cinematicSprites;
|
||||
public PlayableAsset cinematicToPlay;
|
||||
|
||||
// Dictionary to track addressable handles by PlayableDirector
|
||||
private Dictionary<PlayableDirector, AsyncOperationHandle<PlayableAsset>> _addressableHandles
|
||||
= new Dictionary<PlayableDirector, AsyncOperationHandle<PlayableAsset>>();
|
||||
|
||||
public static CinematicsManager Instance
|
||||
{
|
||||
get
|
||||
@@ -41,8 +43,24 @@ namespace CinematicsM
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
|
||||
// Subscribe to application quit event to ensure cleanup
|
||||
Application.quitting += OnApplicationQuit;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
// Unsubscribe from application quit event
|
||||
Application.quitting -= OnApplicationQuit;
|
||||
|
||||
// Clean up any remaining addressable handles when disabled
|
||||
ReleaseAllHandles();
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
ReleaseAllHandles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays a cinematic from an object reference and returns the PlayableDirector playing the timeline
|
||||
/// </summary>
|
||||
@@ -59,6 +77,9 @@ namespace CinematicsM
|
||||
{
|
||||
cinematicSprites.enabled = false;
|
||||
Debug.Log("Cinematic stopped!");
|
||||
|
||||
// Release the addressable handle associated with this director
|
||||
ReleaseAddressableHandle(director);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,18 +87,73 @@ namespace CinematicsM
|
||||
/// </summary>
|
||||
public PlayableDirector LoadAndPlayCinematic(string key)
|
||||
{
|
||||
// Load the asset via addressables
|
||||
var handle = Addressables.LoadAssetAsync<PlayableAsset>(key);
|
||||
var result = handle.WaitForCompletion();
|
||||
|
||||
// Store the handle for later release
|
||||
_addressableHandles[playableDirector] = handle;
|
||||
|
||||
Debug.Log($"[CinematicsManager] Loaded addressable cinematic: {key}");
|
||||
|
||||
return PlayCinematic(result);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
private void Awake()
|
||||
/// <summary>
|
||||
/// Skips the currently playing cinematic if one is active
|
||||
/// </summary>
|
||||
public void SkipCurrentCinematic()
|
||||
{
|
||||
if (playableDirector != null && playableDirector.state == PlayState.Playing)
|
||||
{
|
||||
Debug.Log("Skipping current cinematic");
|
||||
playableDirector.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a cinematic is currently playing
|
||||
/// </summary>
|
||||
public bool IsCinematicPlaying()
|
||||
{
|
||||
return playableDirector != null && playableDirector.state == PlayState.Playing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the addressable handle associated with a specific PlayableDirector
|
||||
/// </summary>
|
||||
private void ReleaseAddressableHandle(PlayableDirector director)
|
||||
{
|
||||
if (_addressableHandles.TryGetValue(director, out var handle))
|
||||
{
|
||||
Debug.Log($"[CinematicsManager] Releasing addressable handle for cinematic");
|
||||
Addressables.Release(handle);
|
||||
_addressableHandles.Remove(director);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all active addressable handles
|
||||
/// </summary>
|
||||
private void ReleaseAllHandles()
|
||||
{
|
||||
foreach (var handle in _addressableHandles.Values)
|
||||
{
|
||||
if (handle.IsValid())
|
||||
{
|
||||
Addressables.Release(handle);
|
||||
}
|
||||
}
|
||||
_addressableHandles.Clear();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (!SceneManager.GetActiveScene().name.ToLower().Contains("mainmenu"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_instance = this;
|
||||
playableDirector = GetComponent<PlayableDirector>();
|
||||
cinematicSprites = GetComponentInChildren<Image>(true);
|
||||
|
||||
112
Assets/Scripts/Cinematics/SkipCinematic.cs
Normal file
112
Assets/Scripts/Cinematics/SkipCinematic.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using Input;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cinematics
|
||||
{
|
||||
public class SkipCinematic : MonoBehaviour, ITouchInputConsumer
|
||||
{
|
||||
[Header("Configuration")]
|
||||
[SerializeField] private float holdDuration = 2.0f;
|
||||
[SerializeField] private Image radialProgressBar;
|
||||
|
||||
private float _holdStartTime;
|
||||
private bool _isHolding;
|
||||
private bool _skipPerformed;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Reset the progress bar
|
||||
if (radialProgressBar != null)
|
||||
{
|
||||
radialProgressBar.fillAmount = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Register as override consumer when enabled
|
||||
InputManager.Instance.RegisterOverrideConsumer(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
// Unregister when disabled
|
||||
InputManager.Instance.UnregisterOverrideConsumer(this);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Only process while cinematic is playing and we're holding
|
||||
if (_isHolding && CinematicsManager.Instance.IsCinematicPlaying())
|
||||
{
|
||||
float holdTime = Time.time - _holdStartTime;
|
||||
float progress = Mathf.Clamp01(holdTime / holdDuration);
|
||||
|
||||
// Update progress bar
|
||||
if (radialProgressBar != null)
|
||||
{
|
||||
radialProgressBar.fillAmount = progress;
|
||||
}
|
||||
|
||||
// Check if we've held long enough to skip
|
||||
if (progress >= 1.0f && !_skipPerformed)
|
||||
{
|
||||
_skipPerformed = true;
|
||||
DoSkipCinematic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoSkipCinematic()
|
||||
{
|
||||
CinematicsManager.Instance.SkipCurrentCinematic();
|
||||
Debug.Log("Cinematic skipped via touch hold");
|
||||
|
||||
// Reset UI
|
||||
if (radialProgressBar != null)
|
||||
{
|
||||
radialProgressBar.fillAmount = 0f;
|
||||
}
|
||||
|
||||
// Remember to clear up input override
|
||||
InputManager.Instance.UnregisterOverrideConsumer(this);
|
||||
}
|
||||
|
||||
#region ITouchInputConsumer Implementation
|
||||
public void OnTap(Vector2 position)
|
||||
{
|
||||
// Not using tap for skipping
|
||||
}
|
||||
|
||||
public void OnHoldStart(Vector2 position)
|
||||
{
|
||||
// Start tracking hold time
|
||||
_isHolding = true;
|
||||
_skipPerformed = false;
|
||||
_holdStartTime = Time.time;
|
||||
|
||||
Debug.Log("Starting cinematic skip gesture");
|
||||
}
|
||||
|
||||
public void OnHoldMove(Vector2 position)
|
||||
{
|
||||
// Hold movement is tracked in Update method
|
||||
}
|
||||
|
||||
public void OnHoldEnd(Vector2 position)
|
||||
{
|
||||
// Reset state when hold ends
|
||||
_isHolding = false;
|
||||
|
||||
// Reset UI
|
||||
if (radialProgressBar != null)
|
||||
{
|
||||
radialProgressBar.fillAmount = 0f;
|
||||
}
|
||||
|
||||
Debug.Log("Cinematic skip gesture canceled");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Cinematics/SkipCinematic.cs.meta
Normal file
2
Assets/Scripts/Cinematics/SkipCinematic.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5526348c1593f9b43987b0edcaccdd24
|
||||
@@ -1,12 +1,8 @@
|
||||
using UnityEngine;
|
||||
using Interactions;
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Core.Settings;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using CinematicsM;
|
||||
using Cinematics;
|
||||
using Core;
|
||||
using Input;
|
||||
using Minigames.DivingForPictures;
|
||||
using PuzzleS;
|
||||
|
||||
namespace AppleHills.Core
|
||||
|
||||
@@ -31,6 +31,9 @@ namespace Input
|
||||
// Override consumer stack - using a list to support multiple overrides that can be removed in LIFO order
|
||||
private readonly List<ITouchInputConsumer> _overrideConsumers = new List<ITouchInputConsumer>();
|
||||
|
||||
// Track which consumer is handling the current hold operation
|
||||
private ITouchInputConsumer _activeHoldConsumer;
|
||||
|
||||
public static InputManager Instance
|
||||
{
|
||||
get
|
||||
@@ -193,6 +196,18 @@ namespace Input
|
||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||
Debug.Log($"[InputManager] HoldMove started at {worldPos2D}");
|
||||
|
||||
// First check for override consumers
|
||||
if (_overrideConsumers.Count > 0)
|
||||
{
|
||||
_activeHoldConsumer = _overrideConsumers[_overrideConsumers.Count - 1];
|
||||
Debug.Log($"[InputManager] Hold delegated to override consumer: {_activeHoldConsumer}");
|
||||
_activeHoldConsumer.OnHoldStart(worldPos2D);
|
||||
return;
|
||||
}
|
||||
|
||||
// If no override consumers, use default consumer
|
||||
_activeHoldConsumer = defaultConsumer;
|
||||
defaultConsumer?.OnHoldStart(worldPos2D);
|
||||
}
|
||||
|
||||
@@ -207,7 +222,10 @@ namespace Input
|
||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||
Debug.Log($"[InputManager] HoldMove canceled at {worldPos2D}");
|
||||
defaultConsumer?.OnHoldEnd(worldPos2D);
|
||||
|
||||
// Notify the active hold consumer that the hold has ended
|
||||
_activeHoldConsumer?.OnHoldEnd(worldPos2D);
|
||||
_activeHoldConsumer = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -221,7 +239,9 @@ namespace Input
|
||||
Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
|
||||
Vector2 worldPos2D = new Vector2(worldPos.x, worldPos.y);
|
||||
// Debug.Log($"[InputManager] HoldMove update at {worldPos2D}");
|
||||
defaultConsumer?.OnHoldMove(worldPos2D);
|
||||
|
||||
// Send hold move updates to the active hold consumer
|
||||
_activeHoldConsumer?.OnHoldMove(worldPos2D);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,6 +362,12 @@ namespace Input
|
||||
if (consumer == null || !_overrideConsumers.Contains(consumer))
|
||||
return;
|
||||
|
||||
// If this is the active hold consumer, reset it
|
||||
if (_activeHoldConsumer == consumer)
|
||||
{
|
||||
_activeHoldConsumer = null;
|
||||
}
|
||||
|
||||
_overrideConsumers.Remove(consumer);
|
||||
Debug.Log($"[InputManager] Override consumer unregistered: {consumer}");
|
||||
}
|
||||
@@ -351,6 +377,7 @@ namespace Input
|
||||
/// </summary>
|
||||
public void ClearOverrideConsumers()
|
||||
{
|
||||
_activeHoldConsumer = null;
|
||||
_overrideConsumers.Clear();
|
||||
Debug.Log("[InputManager] All override consumers cleared.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user