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] private List _characterBackgrounds; [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 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(); } public void Initialize() { if (_instance == null) _instance = this; ConfigureBackgroundPlayer(_primaryPlayer); ConfigureBackgroundPlayer(_secondaryPlayer); _activeBackgroundPlayer = _primaryPlayer; PlayBackgroundImmediately(_menuBackground); } public static void CrossFadeToCharacter(int characterIndex) { if (characterIndex < 0 || characterIndex >= _instance._characterBackgrounds.Count) { Debug.LogError($"Не найден видеофон для персонажа с индексом {characterIndex}"); return; } _instance.StartCrossFade(_instance._characterBackgrounds[characterIndex]); } 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); 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(); _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(); } private VideoPlayer GetInactivePlayer() => _activeBackgroundPlayer == _primaryPlayer ? _secondaryPlayer : _primaryPlayer; private void PlayBackgroundImmediately(VideoClip clip) { _secondaryPlayer.Stop(); _secondaryPlayer.targetCameraAlpha = 0f; _activeBackgroundPlayer.Stop(); _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(); _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(); } }