I'm writing a program in Unity and am using a TextMeshProUGUI object (named history) to hold a list of messages to act as a terminal/console.
The problem I am having is that I am printing up to hundreds of lines a second, which can be detrimental to performance when I'm doing many string splits and then updating the text variable of the TextMeshProUGUI object, (which in turn gets rendered) every single frame.
My initial implementation looked like this:
private const int MAX_HISTORY = 64; // the maximum number of lines to store
public TextMeshProUGUI history; // value is set in Unity editor
private int inputs = 0; // the size of the history object
public void Print(params string[] msgs)
{
// add all messages to the history
foreach (string msg in msgs)
{
if (msg == null)
continue;
inputs++;
history.text += msg + '\n';
}
// and now reduce the size
if (inputs > MAX_HISTORY)
{
string[] lines = history.text.Split('\n');
history.text = "";
for (int i = inputs - MAX_HISTORY; i < lines.Length; i++)
{
history.text += lines[i] + '\n';
}
inputs = MAX_HISTORY;
}
}
and I have managed to reduce it to this:
public void Print(params string[] msgs)
{
foreach (string msg in msgs)
{
if (msg == null)
continue;
inputs++;
history.text += msg + '\n';
}
if (inputs > MAX_HISTORY)
{
history.text =
history.text.Split(new char[] { '\n' }, inputs - MAX_HISTORY)[inputs - MAX_HISTORY - 1];
inputs = MAX_HISTORY;
}
}
But I am still concerned with the line in the if-statement with the large split function. I would appreciate it if somebody who has experience with C# and string manipulation could review this and tell me if my optimisation is (a) correct and (b) good.
Edit:
Changing the value of TextMeshProUGUI.text causes a layout and vertex recalculation which has poor performance so I've also added a StringBuilder to handle the concatenation and splits before setting the text value.
public void Print(params string[] msgs)
{
StringBuilder text = new StringBuilder(history.text);
foreach (string msg in msgs)
{
if (msg == null)
continue;
inputs++;
text.AppendLine(msg);
}
while (inputs > MAX_HISTORY)
{
text.Remove(0, Convert.ToString(text).Split('\n').FirstOrDefault().Length + 1);
inputs = MAX_HISTORY;
}
history.text = text.ToString();
}