Files
2026-05-21 16:04:49 +02:00

102 lines
3.1 KiB
C#

using Cysharp.Threading.Tasks;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.VFX;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class BuildingDeleteAnimation : MonoBehaviour
{
private static readonly int IntensityPropertyID = Shader.PropertyToID("Intensity");
private static readonly int SizePropertyID = Shader.PropertyToID("Size");
[SerializeField]
[ReadOnly]
private float _sinkingHeight;
[SerializeField]
private float _sinkingSpeed = 1;
[SerializeField]
private AnimationCurve _sinkingSpeedCurve = AnimationCurve.Constant(0, 1, 1);
[SerializeField]
private float _shakeFrequency = 10;
[SerializeField]
private float _shakeAmplitude = 0.1f;
[SerializeField]
private VisualEffect _vfxPrefab;
[SerializeField]
private int _vfxCount = 1;
[SerializeField]
private float _vfxInterval = 1;
[SerializeField]
private float _vfxIntensityDecay = 0.5f;
private void ComputeSinkingHeight()
{
var bounds = default(Bounds);
var renderers = GetComponentsInChildren<Renderer>();
foreach (var renderer in renderers) bounds.Encapsulate(renderer.bounds);
_sinkingHeight = bounds.size.y;
}
private void Awake()
{
if (_sinkingHeight == 0) ComputeSinkingHeight();
}
public async UniTask PlayAsync(Building building)
{
var initialPosition = transform.position;
var animatedPosition = transform.position;
var angularFrequency = 2 * Mathf.PI * _shakeFrequency;
var shakeWeights = new Vector3(Random.Range(-1, 1), 0, Random.Range(-1, 1));
for (var i = 0; i < _vfxCount; i++)
{
var delay = i * _vfxInterval;
var intensity = Mathf.Pow(_vfxIntensityDecay, i);
_ = PlayVfxAsync(building, initialPosition, delay, intensity);
}
var t = 0f;
while (animatedPosition.y > initialPosition.y - _sinkingHeight)
{
var dt = Time.deltaTime;
t += dt;
var sinkingSpeed = _sinkingSpeed * _sinkingSpeedCurve.Evaluate(t);
animatedPosition += Vector3.down * (sinkingSpeed * dt);
var shake = Mathf.Sin(t * angularFrequency) * _shakeAmplitude * _sinkingSpeed;
transform.position = animatedPosition + shake * shakeWeights;
await UniTask.NextFrame();
}
}
private async UniTask PlayVfxAsync(Building building, Vector3 position, float delay, float intensity)
{
if (delay > 0) await UniTask.WaitForSeconds(delay);
var vfx = Instantiate(_vfxPrefab, position, Quaternion.identity);
vfx.SetFloat(IntensityPropertyID, intensity);
vfx.SetVector2(SizePropertyID, new Vector2(building.Rect.Width, building.Rect.Height));
}
private void OnValidate()
{
ComputeSinkingHeight();
}
}
}