/// <summary> /// Shows remains letters dynamically /// </summary> /// <param name="text"></param> /// <returns></returns> private IEnumerator ShowRemainingCharacters() { if (!textAnimator.allLettersShown) { isInsideRoutine = true; wantsToSkip = false; onTypewriterStart?.Invoke(); IEnumerator WaitTime(float time) { if (time > 0) { float t = 0; while (t <= time) { t += textAnimator.time.deltaTime; yield return(null); } } } float timeToWait; char characterShown; if (resetTypingSpeedAtStartup) { typewriterPlayerSpeed = 1; } float typewriterTagsSpeed = 1; bool HasSkipped() { return(canSkipTypewriter && wantsToSkip); } float timePassed = 0; float deltaTime; UpdateDeltaTime(); void UpdateDeltaTime() { deltaTime = textAnimator.time.deltaTime * typewriterPlayerSpeed * typewriterTagsSpeed; } //Shows character by character until all are shown while (!textAnimator.allLettersShown) { //searches for actions [before the character, incl. at the very start of the text] if (textAnimator.hasActions) { //loops until features ended (there could be multiple ones in the same text position, example: when two tags are next to eachother without spaces while (textAnimator.TryGetAction(out TypewriterAction action)) { //Default features switch (action.actionID) { case "waitfor": float waitTime; FormatUtils.TryGetFloat(action.parameters, 0, 1f, out waitTime); yield return(WaitTime(waitTime)); break; case "waitinput": yield return(WaitInput()); break; case "speed": FormatUtils.TryGetFloat(action.parameters, 0, 1, out typewriterTagsSpeed); //clamps speed (time cannot go backwards!) if (typewriterTagsSpeed <= 0) { typewriterTagsSpeed = 0.001f; } break; //Action is custom default: yield return(DoCustomAction(action)); break; } } } //increases the visible chars count and stores the new one characterShown = textAnimator.IncreaseVisibleChars(); UpdateDeltaTime(); //triggers event unless it's a space if (characterShown != ' ') { onCharacterVisible?.Invoke(characterShown); } //gets the time to wait based on the newly character showed timeToWait = WaitTimeOf(characterShown); //waiting less time than a frame, we don't wait yet if (timeToWait < deltaTime) { timePassed += timeToWait; if (timePassed >= deltaTime) //waits only if we "surpassed" a frame duration { yield return(null); timePassed %= deltaTime; } } else { while (timePassed < timeToWait && !HasSkipped()) { OnTypewriterCharDelay(); timePassed += deltaTime; yield return(null); UpdateDeltaTime(); } timePassed %= timeToWait; } //Skips typewriter if (HasSkipped()) { textAnimator.ShowAllCharacters(hideAppearancesOnSkip); if (triggerEventsOnSkip) { textAnimator.TriggerRemainingEvents(); } break; } } // triggers the events at the end of the text // // the typewriter is arrived here without skipping // meaning that all events were triggered and we only // have to fire the ones at the very end // (outside tmpro's characters count length) if (!canSkipTypewriter || !wantsToSkip) { textAnimator.TriggerRemainingEvents(); } isInsideRoutine = false; textToShow = string.Empty; //text has been showed, no need to store it now onTextShowed?.Invoke(); } }
/// <summary> /// Typewriter effect /// </summary> /// <param name="text"></param> /// <returns></returns> private IEnumerator ShowVisibleCharacters() { if (!textAnimator.allLettersShown) { isInsideRoutine = true; wantsToSkip = false; float t; onTypewriterStart?.Invoke(); #pragma warning disable 0618 //temp obsolete warning disable or any user that did not implement it will have a warning as well OnTypeWriterStart(); #pragma warning restore 0618 IEnumerator WaitTime(float time) { if (time > 0) { t = 0; while (t <= time) { t += textAnimator.deltaTime; yield return(null); } } } float timeToWait; char characterShown = ' '; typewriterPlayerSpeed = 1; float typewriterTagsSpeed = 1; //Shows character by character until all are shown while (!textAnimator.allLettersShown) { //searches for features if (textAnimator.hasFeatures) { //loops until features ended (there could be multiple ones in the same text position, example: when two tags are next to eachother without spaces while (textAnimator.TryGetFeature(out TextAnimator.CustomTag feature)) { //Default features switch (feature.defaultFeature) { case DefaultFeature.WaitFor: float waitTime; FormatUtils.TryGetFloat(feature.parameters, 0, 1f, out waitTime); yield return(WaitTime(waitTime)); break; case DefaultFeature.WaitInput: yield return(WaitInput()); break; case DefaultFeature.TypewriterSpeedMult: FormatUtils.TryGetFloat(feature.parameters, 0, 1, out typewriterTagsSpeed); //clamps speed (time cannot go backwards!) if (typewriterTagsSpeed <= 0) { typewriterTagsSpeed = 0.001f; } break; } //Custom features if (feature.customFeature != CustomFeature.NotImplemented) { yield return(DoCustomFeature(feature.customFeature, feature.parameters)); } } } characterShown = textAnimator.IncreaseVisibleChars(); t = 0; timeToWait = WaitTimeOf( //get the wait time based characterShown //increases characters ); //triggers event unless it's a space if (characterShown != ' ') { onCharacterVisible?.Invoke(characterShown); } while (t <= timeToWait && !(canSkipTypewriter && wantsToSkip)) { UpdateTypeWriterInput(); t += textAnimator.deltaTime * typewriterPlayerSpeed * typewriterTagsSpeed; yield return(null); } //Skips typewriter if (canSkipTypewriter && wantsToSkip) { textAnimator.ShowAllCharacters(hideAppearancesOnSkip); break; } } isInsideRoutine = false; textToShow = string.Empty; //text has been showed, no need to store it now onTextShowed?.Invoke(); #pragma warning disable 0618 //temp obsolete warning disable or any user that did not implement it will have a warning as well onTypeWriterEnded?.Invoke(); #pragma warning restore 0618 } }