TextAutoTyper.cs


using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.UI;

/// 
/// Author: Tim van den Bosch
/// 
[RequireComponent(typeof(Text))]
[RequireComponent(typeof(TextFader))]
[RequireComponent(typeof(AudioSource))]
public class TextAutoTyper : MonoBehaviour
{
    #region Public variables

    public bool StartTyping = true;                 //Immediately begin typing if this is set to true.
    public bool KeepSentences = false;              //Enable this if you want all sentences to be displayed, line after line.

    [Serializable]
    public class Sentence
    {
        [TextArea(3, 10)]
        public string Line;                         //The line to be typed.
        public float WaitTime = 1f;                 //Waiting time before the next sentence in the list.
        public float CharTime = 0.5f;               //The time the characters are displayed in the sentence.
    }

    public Sentence[] Sentences;                    //The sentences that need to be autotyped
    public int StartSentence = 0;                   //The sentence that begins autotyping.

    public float StartDelay = 0f;                   //Set the starting delay for the whole autotype sequence.
    public bool UseFading = false;                  //Use fading when switching between sentences.
    public bool LastSentenceDisapear = true;        //Make the last sentence disapear or stay. Note: the OnDone will still be called.
    public float LastSentenceTime = 1f;             //The time before the last sentences is done.
    public AudioClip CharSoundClip;                 //The sound for when a character in a sentence has been typed.

    public UnityEvent OnDone;                       //Called when all the sentences are done.

    #endregion 

    #region Private variables

    private Text _DisplayText;
    private bool _IsTyping;
    private bool _StartDelayEnded;

    private float _StartTimer;
    private float _LastSentenceTimer;
    private float _CharTimer;

    private float _SentenceTimer;
    private int _SentenceNum;
    private string _CurrentSentence;
    private bool _GotoNextSentence;

    private TextFader _TextFader;
    private AudioSource _AudioSource;

    #endregion

    // Use this for initialization
    void Start()
    {
        _AudioSource = GetComponent();

        if (Sentences.Length <= 0)
            Debug.LogError("[TextAutotype] No sentences found on gameobject: " + gameObject.name);

        ResetSentences(StartSentence);

        if (StartTyping)
            BeginTyping();
    }

    /// 
    /// Begin the auto typing sequence.
    /// 
    public void BeginTyping()
    {
        _IsTyping = true;
        _StartDelayEnded = false;
    }

    /// 
    /// Reset the who auto typ sequence to his begin status.
    /// 
    /// with which sentence do we start
    public void ResetSentences(int startSentence = 0)
    {
        StartSentence = Mathf.Min(Sentences.Length - 1, startSentence);

        _StartTimer = 0f;
        _CharTimer = 0f;
        _SentenceTimer = 0f;

        _DisplayText = GetComponent();
        _DisplayText.text = "";

        _SentenceNum = StartSentence;
        _CurrentSentence = Sentences[StartSentence].Line;
        _GotoNextSentence = false;

        //Use the fading component if we have fading enabled.
        if (UseFading)
        {
            _TextFader = GetComponent();
            _TextFader.FadeSpeed = 0.8f;
            _TextFader.StartFade = true;
        }
    }

    /// 
    /// Stop the auto type sequence.
    /// 
    public void StopTyping()
    {
        _IsTyping = false;
        _StartTimer = 0f;
    }

    // Update is called once per frame
    void Update()
    {
        if (_IsTyping && Sentences.Length > 0)
        {
            //Start the delay and make sure the starttimer doesn't keep adding up after the delay has ended.
            if (!_StartDelayEnded)
            {
                _StartTimer += Time.deltaTime;
                if (_StartTimer >= StartDelay)
                {
                    _StartTimer = 0f;
                    _StartDelayEnded = true;
                }
            }
            //Check if the start delay has ended, if so begin the autotype sequence.
            else if (_StartDelayEnded)
            {
                if (!_GotoNextSentence)
                {
                    _CharTimer += Time.deltaTime;
                    if (_CharTimer >= Sentences[_SentenceNum].CharTime)
                    {
                        //Autotype the current sentence. If done, goto the next sentence in the list.
                        if (AutoType(_CurrentSentence))
                        {
                            //Fade the text out if isn't the last 
                            if (UseFading && _SentenceNum < (Sentences.Length - 1))
                                _TextFader.BeginFade(TextFader.FadeType.FadeOut, 1f / Sentences[_SentenceNum].WaitTime);

                            _GotoNextSentence = true;
                        }

                        _CharTimer = 0;
                    }
                }
                else
                {
                    //Check if all sentences in the list are done.
                    if (_SentenceNum >= Sentences.Length - 1)
                    {
                        //Wait before the timer has expired. then call the OnDone event and let the last text disapear if enabled.
                        _LastSentenceTimer += Time.deltaTime;
                        if (_LastSentenceTimer >= LastSentenceTime)
                        {
                            //Let the last text disapear. Use fading if enabled.
                            if (LastSentenceDisapear)
                            {
                                if (UseFading)
                                {
                                    _TextFader.BeginFade(TextFader.FadeType.FadeOut, 1f / _LastSentenceTimer);
                                    _TextFader.OnComplete.AddListener(DoneTyping);
                                    _IsTyping = false;
                                }
                                else
                                    DoneTyping();
                            }
                            else
                            {
                                OnDone.Invoke();
                                _IsTyping = false;
                            }
                        }
                    }
                    else
                    {
                        //Get a new sentence, will give old sentence back until sentence time has expired.
                        string newSentence = GetNextSentence();

                        //Use the new sentence and start autotyping it.
                        if (newSentence != _CurrentSentence)
                        {
                            if (UseFading)
                                _TextFader.BeginFade(TextFader.FadeType.FadeIn);

                            //Put all senteces into one string sepperated by an "enter".
                            if (KeepSentences)
                                _CurrentSentence += "\n" + newSentence;
                            else
                            {
                                //Clean up the display text and display the next sentence.
                                _DisplayText.text = "";
                                _CurrentSentence = newSentence;
                            }

                            _CharTimer = 0;
                            _GotoNextSentence = false;
                            _SentenceTimer = 0f;
                        }
                    }
                }
            }
        }
    }

    /// 
    /// Get the next sentence in the list, after an amount of time.
    /// 
    /// 
    private string GetNextSentence()
    {
        _SentenceTimer += Time.deltaTime;
        if (_SentenceTimer >= Sentences[_SentenceNum].WaitTime)
        {
            return Sentences[++_SentenceNum].Line;
        }
        return _CurrentSentence;
    }

    /// 
    /// Autotype the given sentence, returns true if the complete sentence has been typed.
    /// 
    /// 
    /// 
    /// true if the complete sentence has been typed.
    private bool AutoType(string sentence)
    {
        if (Sentences.Length <= 0)
            return false;

        //Calculate which character to type, based on the left characters in the sentence.
        int charNum = _DisplayText.text.Length % (sentence.Length + 1);

        if (charNum < sentence.Length)
        {
            if (CharSoundClip != null)
                _AudioSource.PlayOneShot(CharSoundClip);

            _DisplayText.text += sentence[charNum];
        }

        return charNum == sentence.Length;
    }

    /// 
    /// Hide the current text by displaying an empty text.
    /// 
    public void DoneTyping()
    {
        _StartTimer = 0f;
        _IsTyping = false;
        _DisplayText.text = "";
        OnDone.Invoke();
    }
}