IEnumerator ShootBubbleRoutine(Vector2Int position, bool hasOffset)
    {
        _isShooting = true;

        //Shoot bubble to position
        Vector2 startingPosition  = _currentBubble.transform.position;
        Vector2 finishingPosition = new Vector2(position.x + (hasOffset ? 0.5f : 0), position.y * GameController._yDistanceBetweenCircles);

        Vector3 arrowMidPoint               = arrow.GetPosition(1);
        float   lengthOfFirstSegment        = Vector3.Distance(arrow.GetPosition(0), arrow.GetPosition(1));
        float   lengthOfSecondSegment       = Vector3.Distance(arrow.GetPosition(1), finishingPosition);
        float   timeToCompleteFirstSegment  = lengthOfFirstSegment / (lengthOfFirstSegment + lengthOfSecondSegment);
        float   timeToCompleteSecondSegment = 1 - timeToCompleteFirstSegment;

        float stepSize = Time.fixedDeltaTime * 5;

        for (float i = 0; i < timeToCompleteFirstSegment; i += stepSize)
        {
            _currentBubble.transform.position = EaseMethods.EaseVector2(EaseMethods.GetEase(EaseStyle.LinearEaseInOut), startingPosition, arrowMidPoint, i, timeToCompleteFirstSegment);
            yield return(new WaitForFixedUpdate());
        }
        for (float i = 0; i < timeToCompleteSecondSegment; i += stepSize)
        {
            _currentBubble.transform.position = EaseMethods.EaseVector2(EaseMethods.GetEase(EaseStyle.SineEaseOut), arrowMidPoint, finishingPosition, i, timeToCompleteSecondSegment);
            yield return(new WaitForFixedUpdate());
        }

        //Place bubble on grid
        _currentBubble.transform.position = finishingPosition;
        _currentBubble.GetComponent <CircleCollider2D>().enabled = true;
        BubbleBehaviour currentBubbleComponent = _currentBubble.GetComponent <BubbleBehaviour>();

        _bubblesGrid[position.x, position.y]   = currentBubbleComponent;
        currentBubbleComponent._hasOffset      = hasOffset;
        currentBubbleComponent._positionOnGrid = position;

        Vibration.VibrateGlobal(75);
        foreach (var bubble in GetSurroundingBubbles(currentBubbleComponent._positionOnGrid, true))
        {
            bubble.Push(currentBubbleComponent.transform.position);
        }

        //Try mergin bubbles;
        Vector2Int lastMergedBubblePosition;
        Vector2Int newMergedBubblePosition = position;
        int        comboSize = 0;

        do
        {
            lastMergedBubblePosition = newMergedBubblePosition;
            newMergedBubblePosition  = MergeBubbles(newMergedBubblePosition);
            Vibration.VibrateGlobal(75);
            yield return(new WaitWhile(() => _movingBubbles.Count > 0));

            comboSize++;
        } while (!newMergedBubblePosition.Equals(new Vector2Int(-1, -1)));

        //Explode if more than 2048
        if (GetBubbleAtPosition(lastMergedBubblePosition)._exponent > 10)
        {
            ExplodeAround(lastMergedBubblePosition, 2 + (int)(GetBubbleAtPosition(lastMergedBubblePosition)._exponent - 10));
        }

        yield return(new WaitForSeconds(0.2f));

        bool isAllEmpty = true;

        for (int y = 0; y < _bubblesGrid.GetLength(1); y++)
        {
            if (!IsRowEmpty(y))
            {
                isAllEmpty = false;
                break;
            }
        }

        if (isAllEmpty)
        {
            pool.CreatePerfectText();
            Vibration.VibrateGlobal(300);
        }

        if (position.y == 0)
        {
            MoveAllBubblesUp();
        }

        if (IsRowEmpty(1))
        {
            MoveAllBubblesDown();
        }

        if (IsRowEmpty(2))
        {
            MoveAllBubblesDown();
        }

        if (IsRowEmpty(3))
        {
            MoveAllBubblesDown();
        }

        if (IsRowEmpty(4))
        {
            MoveAllBubblesDown();
        }

        Vector3 currentScale = _nextBubble.transform.localScale;

        startingPosition = _nextBubble.transform.position;
        for (float i = 0; i < 1; i += Time.fixedDeltaTime * 5)
        {
            _nextBubble.transform.localScale = EaseMethods.EaseVector3(EaseMethods.GetEase(EaseStyle.BackEaseOut), currentScale, new Vector3(1, 1, 1), i, 1);
            _nextBubble.transform.position   = EaseMethods.EaseVector2(EaseMethods.GetEase(EaseStyle.SineEaseOut), startingPosition, new Vector2(2.75f, -3), i, 1);
            yield return(new WaitForFixedUpdate());
        }
        _nextBubble.transform.localScale = new Vector3(1, 1, 1);
        _nextBubble.transform.position   = new Vector2(2.75f, -3);
        _currentBubble = _nextBubble;
        _nextBubble    = pool.CreateBubble(new Vector3(1.5f, -3)).gameObject;
        _nextBubble.transform.localScale = new Vector3(0.75f, 0.75f, 1);
        _nextBubble.GetComponent <BubbleBehaviour>()._exponent = GetRandomExponent();
        _nextBubble.GetComponent <BubbleBehaviour>().Refresh();
        _nextBubble.GetComponent <CircleCollider2D>().enabled = false;
        _isShooting = false;
    }