C# Auto Type speed problem.

Hi, I`m currently using a function to make a Auto Type, where letters are going to appear in a interval of time.
Here is the snippet:

    IEnumerator testeA()
    {
        while(textQueue.Peek() != null)
        {
            if(teste)
            {
                char nextChar = (char) textQueue.Dequeue();
                dialogueField.text += nextChar;

            }

            yield return WaitForEndOfFrame();
        }
    }

In this snippet I want to make the text appear on a frame basis, so it should be at least 60 chars per second (since my game is running at 60fps) but it is very slow, something like 1 char by 10 frames or so.

Anyone knows what maybe I`m doing wrong?
Thank you.

There are a couple of issues with this way of going about it, but to be honest I don’t see how it’s causing the result you’re seeing - as far as I can tell it should, if anything, be going too fast.

However, if you want your characters to appear over an interval of time, you don’t want that to be framerate-dependent. You want it to be a function of time. If your player slows to 5 fps for some reason, you don’t want it to take 12 times as long to type out. In addition, you probably want to be able to directly control the amount of time it takes. Finally, repeatedly using + to concatenate strings generates garbage (which contributes to stuttery framerates).

Here’s what I would do to avoid all those problems, and, presumably, fix your initial one along the way.

IEnumerator type(string stringToType, float duration) {
for (float t=0f;t<duration;t+=Time.deltaTime) {
int charactersTyped = stringToType.Length * t / duration;
dialogueField.text = stringToType.Substring(charactersTyped);
yield return null;
}
dialogueField.text = stringToType;
}

That “for loop using Time.deltaTime + yield” thing is a bit of code that’s incredibly handy in coroutines, by the way. It goes from A to B over a certain amount of time. And you can stick “t / duration” into the last parameter of a Lerp function and it’ll just…you know…lerp.

1 Like

Is your code the actual?

yield return new WaitForEndOfFrame();

Thats probably not what you want it to do anyway, yield return null; is probably better.

This may also be useful.

I don’t think I would use that script - it has most of the same problems as OP’s (garbage generation, max of one letter typed per frame, etc). It also won’t actually type at the advertised speed; it’ll be slightly slower thanks to the remainder of time on the given frame. In other words, it’ll wait for 0.1 sec, but the frame hits at 0.13423 sec; the second letter will attempt to type at 0.23423 sec, but that frame will actually hit at 0.24534 sec; and so on. At t=1 second you definitely won’t have 10 characters typed if the interval is set to 0.1.

So it’s still not really framerate independent, just kinda framerate independent.

1 Like

Well, I made this to experiment, but then realized you can’t wait less time than it takes to process a frame anyway. I stopped there and didn’t really test the timing.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Typer : MonoBehaviour
{
    public enum Timing { Frames, Seconds };
    public Timing UseTime;

    public float Seconds;
    public float Frames;
    public Text TargetText;
    [TextArea]
    public string ReferenceString =
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis erat justo, mollis vel blandit eu, tempus ac nisl. Sed dictum, mauris vel scelerisque convallis, lectus enim molestie risus, sed gravida leo velit eget magna.";
   

    void Start()
    {
        WriteStringToTarget(TargetText, ReferenceString, UseTime == Timing.Frames? Frames : Seconds, UseTime);
    }

    public void WriteStringToTarget(Text target, string jibberish, float time, Timing style)
    {
        StartCoroutine(Type(target, jibberish, time, style));
    }

    IEnumerator Type(Text field, string refString, float time, Timing style)
    {
        TargetText.text = "";

        if (style == Timing.Frames)
        {
            foreach (char t in refString)
            {
                field.text += t;

                for (int i = 0; i < Frames; i++)
                {
                    yield return null;
                }
            }
        }
        else
        {
            foreach (char t in refString)
            {
                field.text += t;
                yield return new WaitForSeconds(time - Time.deltaTime);
            }
        }
    }
}

Hmm, so no one have the same problem as I have. The solution should be print two chars per frame to simulate speed?

Yeah, I thought that might be a decent solution. You can’t get precise “After 10ms, type a character” but you can get “If he wants characters that fast, just print more per frame.”…

And really, this will appear the same visually as it would if you were doing it otherwise. All that actually matters is the speed it appears to be typing and when you’re talking about doing many characters within a single frame the method of getting there is irrelevant (at least, with something like this) since you’ll only see the changes from frame to frame.

Thank you all for the answers. I will try to do this :smile:!

here is a nicer way.

Just use a for loop to dictate the typing speed.

public float Delay = 0.001f;
        public int TypingSpeed = 2;
        public int TextLength = 0;
public float Timer = 0;
public string resultText;
public String sourceText = "Just use a for loop to dictate the typing speed.";

        void TypeText()
        {
          
                if (Timer == 0)
                    Timer = Time.time;
                if (Time.time - Timer >= Delay)
                {
                    Timer = Time.time;
                for (int i = 0; i < TypingSpeed; i++)
                {
                    TextLength += 1;
                    resultText = sourceText .Substring(0, Math.Min(sourceText.Length, TextLength));
                }
                }
        }