chip-gameV3/Assets/Scripts/Media/VideoUtility.cs

260 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.Video;
public class VideoUtility : MonoBehaviour
{
[SerializeField, FormerlySerializedAs("player")] private VideoPlayer _primaryPlayer;
[SerializeField] private VideoPlayer _secondaryPlayer;
[SerializeField, FormerlySerializedAs("audioSource")] private AudioSource _audioSource;
[SerializeField, FormerlySerializedAs("fon")] private VideoClip _menuBackground;
[SerializeField, FormerlySerializedAs("ads")] private VideoClip _ads;
[SerializeField, FormerlySerializedAs("ending")] private VideoClip _ending;
[SerializeField] private float _crossFadeDuration = 1f;
[SerializeField, FormerlySerializedAs("canvas")] private Canvas _canvas;
private static VideoUtility _instance;
private readonly Dictionary<VideoClip, List<System.Action>> _pendingReleases = new();
private VideoPlayer _activeBackgroundPlayer;
private Coroutine _crossFadeCoroutine;
public static float AdsLength => (float)_instance._ads.length;
public static float VictoryLength => (float)_instance._ending.length;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha5))
PlayFon();
if (Input.GetKeyDown(KeyCode.Alpha6))
PlayAds();
if (Input.GetKeyDown(KeyCode.Alpha7))
PlayEnding();
}
private void OnDestroy()
{
SettingsManager.OnSettingsChanged -= ApplyAudioSettings;
foreach (List<System.Action> releases in _pendingReleases.Values)
{
foreach (System.Action release in releases)
release?.Invoke();
}
_pendingReleases.Clear();
if (_instance == this)
_instance = null;
}
public void Initialize()
{
if (_instance == null)
_instance = this;
ConfigureBackgroundPlayer(_primaryPlayer);
ConfigureBackgroundPlayer(_secondaryPlayer);
_activeBackgroundPlayer = _primaryPlayer;
ApplyAudioSettings();
SettingsManager.OnSettingsChanged -= ApplyAudioSettings;
SettingsManager.OnSettingsChanged += ApplyAudioSettings;
PlayBackgroundImmediately(_menuBackground);
}
public static void CrossFadeToCharacter(int characterIndex, VideoClip backgroundVideo)
{
if (backgroundVideo == null)
{
Debug.LogError($"Не найден видеофон для персонажа с индексом {characterIndex}");
return;
}
_instance.StartCrossFade(backgroundVideo);
}
public static void CrossFadeToMenu()
=> _instance.StartCrossFade(_instance._menuBackground);
public static void PlayFon()
=> CrossFadeToMenu();
public static void PlayAds()
=> _instance.PlayForeground(_instance._ads);
public static void PlayEnding()
=> _instance.PlayForeground(_instance._ending);
public static void ReleaseBackgroundWhenUnused(VideoClip clip, System.Action release)
{
if (release == null)
return;
if (_instance == null || clip == null || !_instance.IsClipAssigned(clip))
{
release.Invoke();
return;
}
if (!_instance._pendingReleases.TryGetValue(clip, out List<System.Action> releases))
{
releases = new List<System.Action>();
_instance._pendingReleases[clip] = releases;
}
releases.Add(release);
}
private void StartCrossFade(VideoClip targetClip)
{
if (targetClip == null)
{
Debug.LogError("Не назначен видеофон для переключения");
return;
}
NormalizeInterruptedCrossFade();
if (_activeBackgroundPlayer.clip == targetClip && _activeBackgroundPlayer.isPlaying)
return;
_crossFadeCoroutine = StartCoroutine(CrossFadeCoroutine(targetClip));
}
private IEnumerator CrossFadeCoroutine(VideoClip targetClip)
{
VideoPlayer outgoingPlayer = _activeBackgroundPlayer;
VideoPlayer incomingPlayer = GetInactivePlayer();
ConfigureBackgroundPlayer(incomingPlayer);
incomingPlayer.Stop();
incomingPlayer.clip = targetClip;
incomingPlayer.targetCameraAlpha = 0f;
incomingPlayer.Prepare();
//while (incomingPlayer.isPrepared == false)
// yield return null;
incomingPlayer.Play();
float elapsedTime = 0f;
float duration = Mathf.Max(_crossFadeDuration, 0.01f);
while (elapsedTime < duration)
{
elapsedTime += Time.unscaledDeltaTime;
float progress = Mathf.Clamp01(elapsedTime / duration);
incomingPlayer.targetCameraAlpha = progress;
outgoingPlayer.targetCameraAlpha = 1f - progress;
yield return null;
}
incomingPlayer.targetCameraAlpha = 1f;
outgoingPlayer.targetCameraAlpha = 0f;
outgoingPlayer.Stop();
ReleasePlayerClip(outgoingPlayer);
_activeBackgroundPlayer = incomingPlayer;
_crossFadeCoroutine = null;
}
private void NormalizeInterruptedCrossFade()
{
if (_crossFadeCoroutine == null)
return;
StopCoroutine(_crossFadeCoroutine);
_crossFadeCoroutine = null;
_activeBackgroundPlayer = _primaryPlayer.targetCameraAlpha >= _secondaryPlayer.targetCameraAlpha
? _primaryPlayer
: _secondaryPlayer;
VideoPlayer inactivePlayer = GetInactivePlayer();
_activeBackgroundPlayer.targetCameraAlpha = 1f;
inactivePlayer.targetCameraAlpha = 0f;
inactivePlayer.Stop();
ReleasePlayerClip(inactivePlayer);
}
private VideoPlayer GetInactivePlayer()
=> _activeBackgroundPlayer == _primaryPlayer ? _secondaryPlayer : _primaryPlayer;
private void PlayBackgroundImmediately(VideoClip clip)
{
_secondaryPlayer.Stop();
_secondaryPlayer.targetCameraAlpha = 0f;
ReleasePlayerClip(_secondaryPlayer);
_activeBackgroundPlayer.Stop();
ReleasePlayerClip(_activeBackgroundPlayer);
_activeBackgroundPlayer = _primaryPlayer;
_activeBackgroundPlayer.clip = clip;
_activeBackgroundPlayer.targetCameraAlpha = 1f;
_activeBackgroundPlayer.Play();
}
private void ConfigureBackgroundPlayer(VideoPlayer videoPlayer)
{
videoPlayer.renderMode = VideoRenderMode.CameraFarPlane;
videoPlayer.targetCamera = _primaryPlayer.targetCamera;
videoPlayer.aspectRatio = _primaryPlayer.aspectRatio;
videoPlayer.isLooping = true;
videoPlayer.playOnAwake = false;
videoPlayer.audioOutputMode = VideoAudioOutputMode.None;
}
private void PlayForeground(VideoClip clip)
{
NormalizeInterruptedCrossFade();
_primaryPlayer.Stop();
_secondaryPlayer.Stop();
ReleasePlayerClip(_primaryPlayer);
ReleasePlayerClip(_secondaryPlayer);
_activeBackgroundPlayer = _primaryPlayer;
_primaryPlayer.renderMode = VideoRenderMode.CameraNearPlane;
_primaryPlayer.targetCameraAlpha = 1f;
_primaryPlayer.isLooping = false;
_primaryPlayer.clip = clip;
_primaryPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
_primaryPlayer.EnableAudioTrack(0, true);
_primaryPlayer.SetTargetAudioSource(0, _audioSource);
_audioSource.Stop();
StartCoroutine(PrepareAndPlayForeground());
}
private IEnumerator PrepareAndPlayForeground()
{
_primaryPlayer.Prepare();
while (_primaryPlayer.isPrepared == false)
yield return null;
_audioSource.Play();
_primaryPlayer.Play();
}
private void ApplyAudioSettings()
=> _audioSource.volume = SettingsManager.GetFloat(SettingKey.PROMO_VOLUME);
private bool IsClipAssigned(VideoClip clip)
=> _primaryPlayer.clip == clip || _secondaryPlayer.clip == clip;
private void ReleasePlayerClip(VideoPlayer videoPlayer)
{
VideoClip releasedClip = videoPlayer.clip;
videoPlayer.clip = null;
NotifyClipUnused(releasedClip);
}
private void NotifyClipUnused(VideoClip clip)
{
if (clip == null || IsClipAssigned(clip) || !_pendingReleases.Remove(clip, out List<System.Action> releases))
return;
foreach (System.Action release in releases)
release?.Invoke();
}
}