Unity 2D字符串处理代码引发严重卡顿问题求助
Fixing That Crippling Unity Freeze From Line-Wrapping Text
Hey there, let's break down why your text line-wrapping code is making Unity freeze for 4 minutes and how to fix it fast.
First, let's zero in on the most common pitfalls causing this (even without seeing your full code, these are the usual suspects):
- You’re updating the Text component’s
textproperty in a loop: Every time you modifydisplayText.text, Unity has to recalculate text layout, update the canvas, and trigger expensive rendering logic. Do this hundreds of times, and those tiny costs stack up to minutes of freeze. - You’re using
+for string concatenation: Strings in C# are immutable, so every+=creates a brand new string object. This floods the garbage collector, which makes Unity stutter or freeze while cleaning up all that extra memory.
Here's the Fixed, Efficient Version
We’ll rewrite the code to fix both issues: use a StringBuilder for fast, low-memory string building, and only update the Text component once when we’re done processing.
using System.Text; using UnityEngine; using UnityEngine.UI; public class TextLineWrapper : MonoBehaviour { [SerializeField] private Text targetText; [SerializeField] private Transform panelContainer; // Your panel reference [SerializeField] private int charsPerLine = 71; [SerializeField] private string inputText; // The long string you need to wrap void Start() { WrapTextWithoutFreezing(); } private void WrapTextWithoutFreezing() { if (string.IsNullOrEmpty(inputText) || targetText == null) return; // Optional: Disable layout components temporarily to skip extra recalculations LayoutGroup panelLayout = panelContainer.GetComponent<LayoutGroup>(); bool wasLayoutActive = panelLayout?.enabled ?? false; if (panelLayout != null) panelLayout.enabled = false; // Use StringBuilder to build wrapped text efficiently (no extra string objects!) StringBuilder wrappedText = new StringBuilder(); int totalChars = inputText.Length; for (int i = 0; i < totalChars; i += charsPerLine) { int lineCharCount = Mathf.Min(charsPerLine, totalChars - i); wrappedText.Append(inputText.Substring(i, lineCharCount)); // Skip newline after the final line if (i + lineCharCount < totalChars) { wrappedText.Append("\n"); } } // Update the Text component ONCE, not every line targetText.text = wrappedText.ToString(); // Re-enable layout and force a single rebuild if needed if (panelLayout != null && wasLayoutActive) { panelLayout.enabled = true; LayoutRebuilder.ForceRebuildLayoutImmediate(panelContainer.GetComponent<RectTransform>()); } } }
What If Your String Is Extremely Long?
If you’re dealing with a string that’s tens of thousands of characters long, even the above code might cause a single-frame freeze. For that, use a coroutine to split the work across multiple frames:
private IEnumerator WrapTextOverFrames() { if (string.IsNullOrEmpty(inputText) || targetText == null) yield break; LayoutGroup panelLayout = panelContainer.GetComponent<LayoutGroup>(); bool wasLayoutActive = panelLayout?.enabled ?? false; if (panelLayout != null) panelLayout.enabled = false; StringBuilder wrappedText = new StringBuilder(); int totalChars = inputText.Length; int currentIndex = 0; int linesPerFrame = 100; // Adjust this based on your performance needs while (currentIndex < totalChars) { // Process a chunk of lines per frame for (int j = 0; j < linesPerFrame && currentIndex < totalChars; j++) { int lineCharCount = Mathf.Min(charsPerLine, totalChars - currentIndex); wrappedText.Append(inputText.Substring(currentIndex, lineCharCount)); if (currentIndex + lineCharCount < totalChars) { wrappedText.Append("\n"); } currentIndex += lineCharCount; } // Update text and let Unity render the frame before continuing targetText.text = wrappedText.ToString(); yield return null; // Give control back to Unity for a frame } if (panelLayout != null && wasLayoutActive) { panelLayout.enabled = true; LayoutRebuilder.ForceRebuildLayoutImmediate(panelContainer.GetComponent<RectTransform>()); } }
Quick Checks to Avoid Future Freezes
- Don’t run this in
Update(): Only call the line-wrapping code when your input string changes, not every frame. - Cache your references: If you’re calling
GetComponent<Text>()in the loop, that’s another hidden cost. Cache theTextcomponent inStart()or assign it in the inspector. - Skip unnecessary layout work: Disabling layout components while processing text cuts out tons of extra Unity overhead.
内容的提问来源于stack exchange,提问作者Shane Powell
相关产品推荐
相关产品推荐

