private void SetAtomShaderProperties(RandomAtom current)
 {
     _renderer.material.SetFloat("_NucleusAttraction", current.nucleusAttraction);
     _renderer.material.SetFloat("_NucleusRepulsion", current.nucleusRepulsion);
     _renderer.material.SetFloat("_NucleusSize", current.nucleusSize);
     _renderer.material.SetFloat("_ElectronCount", current.electronCount);
     _renderer.material.SetFloat("_ElectronSize", current.electronSize);
     _renderer.material.SetFloat("_ElectronSpeed", current.electronSpeed);
     _renderer.material.SetFloat("_RadialModifier", current.radialModifier);
 }
    RandomAtom GenerateRandomAtom(RandomAtom previous)
    {
        RandomAtom atom;

        atom.nucleusAttraction = UnityEngine.Random.Range(0f, _randomFactor * NUCLEUS_ATTR_MAX);
        atom.nucleusAttraction = (UnityEngine.Random.Range(0, 2) > 0) ?
                                 Mathf.Max(atom.nucleusAttraction - previous.nucleusAttraction, 0f) :
                                 Mathf.Min(atom.nucleusAttraction + previous.nucleusAttraction, NUCLEUS_ATTR_MAX);

        atom.nucleusRepulsion = UnityEngine.Random.Range(0f, _randomFactor * NUCLEUS_REPL_MAX);
        atom.nucleusRepulsion = (UnityEngine.Random.Range(0, 2) > 0) ?
                                Mathf.Max(atom.nucleusRepulsion - previous.nucleusRepulsion, 0f) :
                                Mathf.Min(atom.nucleusRepulsion + previous.nucleusRepulsion, NUCLEUS_REPL_MAX);

        atom.nucleusSize = UnityEngine.Random.Range(1f, _randomFactor * NUCLEUS_SIZE_MAX);
        atom.nucleusSize = (UnityEngine.Random.Range(0, 2) > 0) ?
                           Mathf.Max(atom.nucleusSize - previous.nucleusSize, 1f) :
                           Mathf.Min(atom.nucleusSize + previous.nucleusSize, NUCLEUS_SIZE_MAX);

        atom.electronSize = UnityEngine.Random.Range(1f, _randomFactor * ELECTR_SIZE_MAX);
        atom.electronSize = (UnityEngine.Random.Range(0, 2) > 0) ?
                            Mathf.Max(atom.electronSize - previous.electronSize, 1f) :
                            Mathf.Min(atom.electronSize + previous.electronSize, ELECTR_SIZE_MAX);

        atom.electronSpeed = UnityEngine.Random.Range(1f, _randomFactor * ELECTR_SPEED_MAX);
        atom.electronSpeed = (UnityEngine.Random.Range(0, 2) > 0) ?
                             Mathf.Max(atom.electronSpeed - previous.electronSpeed, 1f) :
                             Mathf.Min(atom.electronSpeed + previous.electronSpeed, ELECTR_SPEED_MAX);

        atom.radialModifier = UnityEngine.Random.Range(1f, _randomFactor * RADIAL_MAX);
        atom.radialModifier = (UnityEngine.Random.Range(0, 2) > 0) ?
                              Mathf.Max(atom.radialModifier - previous.radialModifier, 1f) :
                              Mathf.Min(atom.radialModifier + previous.radialModifier, RADIAL_MAX);


        if (!StressTest)
        {
            atom.electronCount = UnityEngine.Random.Range(1f, _randomFactor * ELECTR_COUNT_MAX);
            atom.electronCount = (UnityEngine.Random.Range(0, 2) > 0) ?
                                 Mathf.Max(atom.electronCount - previous.electronCount, 1f) :
                                 Mathf.Min(atom.electronCount + previous.electronCount, ELECTR_COUNT_MAX);
        }
        else
        {
            atom.electronCount = Mathf.Min(previous.electronCount + STRESS_ADDITION, ELECTR_COUNT_STRESS);
        }

        return(atom);
    }
    private bool LerpAtomFields(ref RandomAtom current, RandomAtom next, float t)
    {
        if (Mathf.Abs(current.electronSpeed - next.electronSpeed) < 1.5)
        {
            return(false);
        }

        current.nucleusAttraction = Mathf.Lerp(current.nucleusAttraction, next.nucleusAttraction, t);
        current.nucleusRepulsion  = Mathf.Lerp(current.nucleusRepulsion, next.nucleusRepulsion, t);
        current.nucleusSize       = Mathf.Lerp(current.nucleusSize, next.nucleusSize, t);
        current.electronCount     = Mathf.Lerp(current.electronCount, next.electronCount, t);
        current.electronSize      = Mathf.Lerp(current.electronSize, next.electronSize, t);
        current.electronSpeed     = Mathf.Lerp(current.electronSpeed, next.electronSpeed, t);
        current.radialModifier    = Mathf.Lerp(current.radialModifier, next.radialModifier, t);
        return(true);
    }
    private IEnumerator AtomShaderCoroutine()
    {
        _renderer.material.SetColor("_ForegroundColor", _foregroundColor);
        _renderer.material.SetColor("_BackgroundColor", _backgroundColor);

        _renderer.material.SetFloat("_RandomForegroundColor", (_randomizeForeground) ? 1f : 0f);
        _renderer.material.SetFloat("_RandomBackgroundColor", (_randomizeBackground) ? 1f : 0f);

        bool prevForegroundSet = _randomizeForeground;
        bool prevBackgroundSet = _randomizeBackground;

        Color32 prevForeColor = _foregroundColor;
        Color32 prevBackColor = _backgroundColor;

        float stateTime = 0.0f;

        RandomAtom nextAtom       = new RandomAtom();
        RandomAtom prevRandomAtom = new RandomAtom
                                    (
            _renderer.material.GetFloat("_NucleusAttraction"),
            _renderer.material.GetFloat("_NucleusRepulsion"),
            _renderer.material.GetFloat("_NucleusSize"),
            _renderer.material.GetFloat("_ElectronCount"),
            _renderer.material.GetFloat("_ElectronSize"),
            _renderer.material.GetFloat("_ElectronSpeed"),
            _renderer.material.GetFloat("_RadialModifier")
                                    );

        while (true)
        {
            if (prevForegroundSet != _randomizeForeground)
            {
                _renderer.material.SetFloat("_RandomForegroundColor", (_randomizeForeground) ? 1f : 0f);
                prevForegroundSet = _randomizeForeground;
            }

            if (prevBackgroundSet != _randomizeBackground)
            {
                _renderer.material.SetFloat("_RandomBackgroundColor", (_randomizeBackground) ? 1f : 0f);
                prevBackgroundSet = _randomizeBackground;
            }

            if (!EqualColor(prevForeColor, _foregroundColor))
            {
                _renderer.material.SetColor("_ForegroundColor", _foregroundColor);
                prevForeColor = _foregroundColor;
            }

            if (!EqualColor(prevBackColor, _backgroundColor))
            {
                _renderer.material.SetColor("_BackgroundColor", _backgroundColor);
                prevBackColor = _backgroundColor;
            }

            if (!_randomizeAtomFields)
            {
                yield return(null);

                continue;
            }

            if (_invokeRandom)
            {
                nextAtom      = GenerateRandomAtom(prevRandomAtom);
                _invokeRandom = false;
                yield return(null);

                continue;
            }
            else
            {
                if (LerpAtomFields(ref prevRandomAtom, nextAtom, Time.deltaTime))
                {
                    SetAtomShaderProperties(prevRandomAtom);
                    yield return(new WaitForSeconds(Time.deltaTime));

                    continue;
                }
                else
                {
                    // Hold time in this random state
                    if (stateTime < ATOM_STATE_TIME)
                    {
                        yield return(new WaitForSeconds(Time.deltaTime));

                        stateTime += Time.deltaTime;
                        continue;
                    }
                    else
                    {
                        stateTime     = 0.0f;
                        _invokeRandom = true;
                        yield return(null);

                        continue;
                    }
                }
            }
        }
    }