private IEnumerator ConversionAnimation(int n, BlockDefinition def, System.Action callback)
        {
            float duration = (REMOVING_DURATION + (n * DURATION_BETWEEN_BLOCKS));

            float s = 15f;
            float p = 0f;
            float d = 1f;

            while (duration > 0)
            {
                duration -= Time.deltaTime;

                // Blink
                p += d * s * Time.deltaTime;
                if (p > 1f || p < 0f)
                {
                    d = -d;
                }

                spriteRenderer.color = Color.Lerp(Color.white, Color.white * 0.5f, p);

                yield return(new WaitForEndOfFrame());
            }

            spriteRenderer.color = Color.white;

            if (def != null)
            {
                spriteRenderer.sprite = def.sprite;
            }
            else
            {
                spriteRenderer.sprite = null;
            }

            callback.Raise();
        }
        private IEnumerator EmptyAnimation(int n, int count, System.Action callback)
        {
            spriteRenderer.sortingOrder += 10 + n;
            int remaining = count - n;

            // Easy constants access
            //---------------------------------------------------

            // Timings
            const float BLINK_DURATION = 0.5f;
            const float GROW_DURATION  = 0.15f;
            const float WAIT_BEFORE_EXPLOSION_DURATION = 0.2f;
            const float EXPLOSION_DURATION             = 0.1f;
            const float EXPLOSION_DURATION_SHIFT       = 0.1f;

            // Values
            const float GROW_SCALE_BONUS = 0.105f;

            //---------------------------------------------------

            if (IsHidden)
            {
                Reveal(0, 2.5f);
            }

            // Blink fade
            spriteRenderer.DOFade(0.5f, 0.1f).SetLoops(-1, LoopType.Yoyo);

            yield return(new WaitForSeconds(BLINK_DURATION));

            spriteRenderer.DOKill();
            spriteRenderer.DOFade(0.75f, 0f);

            // Grow...
            var previousScale = transform.localScale;

            StartCoroutine(Interpolators.Curve(Interpolators.EaseOutCurve, 0f, 1f, GROW_DURATION,
                                               (step) =>
            {
                transform.localScale = Vector3.one * (1 + (GROW_SCALE_BONUS * step));

                Vector3 shitToCenter = (transform.localScale - previousScale);
                shitToCenter.x       = -shitToCenter.x / 2f;
                shitToCenter.y       = 0;

                shift = shitToCenter;
            }, null));

            yield return(new WaitForSeconds(GROW_DURATION + WAIT_BEFORE_EXPLOSION_DURATION));

            // Wait
            var duration = (n * EXPLOSION_DURATION_SHIFT);

            yield return(new WaitForSeconds(duration));

            // Block disappear
            spriteRenderer.DOFade(0f, 0.15f).SetEase(Ease.InCubic)
            .SetDelay(0.1f);

            yield return(new WaitForSeconds(EXPLOSION_DURATION));

            OnEmpty.Raise(block.Definition);

            // THIS synchronize falls between all blocks.
            yield return(new WaitForSeconds(remaining * EXPLOSION_DURATION_SHIFT));

            // Reset
            shift = Vector2.zero;
            transform.localScale = Vector3.one;

            spriteRenderer.sortingOrder -= 10 + n;

            callback.Raise();
        }