102 lines
3.1 KiB
C#
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();
|
|
}
|
|
}
|
|
} |