using System.Collections.Generic; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Playables; using UnityEngine.VFX; namespace DanieleMarotta.RiversongCodeShowcase { [RequireComponent(typeof(Animator))] public class BuildingPlacementAnimation : MonoBehaviour, IAnimationClipSource { [SerializeField] private AnimationClip _animationClip; [SerializeField] private float _playbackSpeed = 1; [SerializeField] private Vector3 _positionLerpWeights = new(1.5f, 1, 1.5f); [SerializeField] private float _rotationLerpWeight = 1.5f; [SerializeField] private VisualEffect _impactVfxPrefab; [SerializeField] private float _impactIntensityDecay = 0.75f; [SerializeField] [HideInInspector] private float _animationProgress; [SerializeField] [HideInInspector] private float _bounce; private PlayableGraph _playableGraph; private AnimationClipPlayable _playableClip; private BuildingDefinition _building; private Vector3 _startPosition; private Vector3 _finalPosition; private Quaternion _finalRotation; public bool IsPlaying { get; private set; } private void Awake() { _playableGraph = PlayableGraph.Create(); _playableGraph.SetTimeUpdateMode(DirectorUpdateMode.Manual); _playableClip = AnimationClipPlayable.Create(_playableGraph, _animationClip); _playableClip.SetSpeed(_playbackSpeed); var animator = GetComponent(); var output = AnimationPlayableOutput.Create(_playableGraph, nameof(BuildingPlacementAnimation), animator); output.SetSourcePlayable(_playableClip); } private void OnDestroy() { _playableGraph.Destroy(); } private void Update() { if (!IsPlaying) return; _playableGraph.Evaluate(Time.unscaledDeltaTime); var position = transform.position; position.x = Mathf.Lerp(_startPosition.x, _finalPosition.x, _positionLerpWeights.x * _animationProgress); position.y = Mathf.Lerp(_startPosition.y, _finalPosition.y, _positionLerpWeights.y * _bounce); position.z = Mathf.Lerp(_startPosition.z, _finalPosition.z, _positionLerpWeights.z * _animationProgress); transform.position = position; transform.rotation = Quaternion.Lerp(transform.rotation, _finalRotation, _rotationLerpWeight * _animationProgress); } public async UniTask PlayAsync(BuildingDefinition building, Vector3 startPosition, Vector3 finalPosition, Quaternion finalRotation) { IsPlaying = true; _building = building; _startPosition = startPosition; _finalPosition = finalPosition; _finalRotation = finalRotation; _playableClip.SetTime(0); _playableClip.SetTime(0); _playableGraph.Play(); _animationProgress = 0; while (_animationProgress < 1) await UniTask.NextFrame(); _playableGraph.Stop(); transform.SetPositionAndRotation(finalPosition, finalRotation); IsPlaying = false; } public void GetAnimationClips(List results) { if (_animationClip) results.Add(_animationClip); } private void OnImpact(int impact) { var impactVfx = Instantiate(_impactVfxPrefab, transform.position, transform.rotation); var intensity = Mathf.Pow(_impactIntensityDecay, impact); var size = new Vector2(_building.Width, _building.Height); DustVfxProperties.Setup(impactVfx, intensity, size); } } }