Unity中字符串第0位索引显示异常问题求助
打字小游戏文本显示异常问题
我正在开发一款打字玩法的小游戏,从文本文件读取内容解析为List<string>,字符串加载正常,但输出时出现异常:第一句显示正常,从第二句开始首字符总是错误,规律如下:
- sentence1 [正常显示sentence1]
- sentence2 [显示sentence1的首字符]
- sentence3 [显示sentence2的首字符]
复制对象后首次运行正常,切换场景或多次运行后又会出错。该对象是Prefab,在多个关卡使用,部分关卡异常更频繁,部分关卡90%正常。
相关脚本代码
初始WriteTextProlog脚本
public class WriteTextProlog : MonoBehaviour { public string givenSentence; [SerializeField] private TMP_Text textArea; [SerializeField] private float writeOutDelay; private float _writeCounter; private int _position; [SerializeField] private WriteOutSentences writeOutSentences; protected void Update() { if (!writeOutSentences.writeNewSentence) { return; } if (_writeCounter < writeOutDelay) { _writeCounter += Time.deltaTime; return; } if (_position >= givenSentence.Length) { writeOutSentences.writeNewSentence = false; writeOutSentences.interactText.textForInteraction = givenSentence; writeOutSentences.ableToWriteInto = true; _position = 0; return; } Debug.Log(givenSentence); textArea.text += givenSentence[_position++]; writeOutSentences.ableToWriteInto = false; _writeCounter = 0f; } }
完整WriteOutSentences脚本
using System; using System.Collections; using System.Collections.Generic; using TMPro; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; public class WriteOutSentences : MonoBehaviour { public UnityEvent successfulInteraction; [SerializeField] private WriteTextProlog writeText; [SerializeField] public InteractTextPrologWritingSentences interactText; [Header("File")] private readonly List<string> _sentenceList = new(); [SerializeField] private TextAsset myFile; private int _numberOfSentences; public bool interacting; [Header("Text fields")] [SerializeField] public TMP_Text ownTextField; [SerializeField] public WritingGameplayProlog writing; public int rowIndex; public bool writeNewSentence; public bool ableToWriteInto; private void Start() { LoadStrings(); _numberOfSentences = _sentenceList.Count; } private void Update() { if (!interacting) { return; } if (!writeNewSentence) { return; } if (rowIndex < _numberOfSentences) { writeText.givenSentence = _sentenceList[rowIndex]; } else { writing.controlWordsProlog.canMove = true; Destroy(gameObject); } } private void LoadStrings() { var textFromFile = myFile.ToString(); var lines = textFromFile.Split(Environment.NewLine.ToCharArray()); foreach (var line in lines) { if (!line.Equals("")) { _sentenceList.Add(line); } } } private void OnTriggerEnter2D(Collider2D other) { interacting = true; writing.controlWordsProlog.stopWritingTimer = true; writing.controlWordsProlog.canMove = false; writing.ChangeTextArea(ownTextField); writeNewSentence = true; interactText.interactable = true; } public int ReturnNumOfLines() { return _sentenceList.Count; } }
InteractTextPrologWritingSentences脚本(rowIndex递增逻辑)
public class InteractTextPrologWritingSentences : MonoBehaviour { public string textForInteraction; [SerializeField] private WritingGameplayProlog writing; [SerializeField] private WriteOutSentences writeOutSentences; [SerializeField] private TMP_Text textArea; public bool interactable; private enum ReturnMeanings {EmptyWord, NotMatchingLetter, MatchingLetter}; private void Update() { if (!interactable) { return; } if (!writeOutSentences.ableToWriteInto) { return; } var result = CheckIndexes(writing.ReturnText()); switch (result) { case (int)ReturnMeanings.EmptyWord: return; case (int)ReturnMeanings.NotMatchingLetter: writing.ClearText(); break; } if (writing.ReturnText().Equals(textForInteraction)) { writing.ClearText(); textArea.text = ""; writeOutSentences.writeNewSentence = true; writeOutSentences.rowIndex++; } } private int CheckIndexes(string textFromField) { if (textFromField.Length == 0) { return (int) ReturnMeanings.EmptyWord; } if (textFromField.Length > textForInteraction.Length) { return (int)ReturnMeanings.NotMatchingLetter; } for (var i = 0; i < textFromField.Length; i++) { if (textFromField[i] != textForInteraction[i]) { return (int)ReturnMeanings.NotMatchingLetter; } } return (int)ReturnMeanings.MatchingLetter; } }
添加检查后的WriteTextProlog脚本
public class WriteTextProlog : MonoBehaviour { public string givenSentence; [SerializeField] private TMP_Text textArea; [SerializeField] private float writeOutDelay; private float _writeCounter; private int _position; [SerializeField] private WriteOutSentences writeOutSentences; private int _lastRowIndex; private string _lastSentence; private void Start() { _lastSentence = ""; _lastRowIndex = -1; } private void Update() { if (!writeOutSentences.writeNewSentence) { return; } if (_writeCounter < writeOutDelay) { _writeCounter += Time.deltaTime; return; } if (_lastRowIndex == writeOutSentences.rowIndex) { return; } if (_position >= givenSentence.Length) { _lastRowIndex = writeOutSentences.rowIndex; _lastSentence = givenSentence; writeOutSentences.writeNewSentence = false; writeOutSentences.interactText.textForInteraction = givenSentence; writeOutSentences.ableToWriteInto = true; _position = 0; return; } if (_lastSentence.Equals(givenSentence)) { return; } Debug.Log(givenSentence); Debug.Log(_position +":" + givenSentence[_position] + ":"+(writeOutSentences.rowIndex)); textArea.text += givenSentence[_position++]; writeOutSentences.ableToWriteInto = false; _writeCounter = 0f; } }
问题根源与修复方案
核心问题
- 多帧同步冲突:
WriteOutSentences.Update持续给givenSentence赋值,而WriteTextProlog切换句子时未及时重置文本区域和位置变量,导致首字符复用上一句的状态。 - Prefab状态残留:对象复用或场景切换时,私有变量(如
_position)未被正确重置,携带旧状态导致异常。
修复代码
1. 优化WriteTextProlog(强制状态重置)
public class WriteTextProlog : MonoBehaviour { public string givenSentence; [SerializeField] private TMP_Text textArea; [SerializeField] private float writeOutDelay; private float _writeCounter; private int _position; [SerializeField] private WriteOutSentences writeOutSentences; private string _currentSentence; private void Update() { if (!writeOutSentences.writeNewSentence) { return; } // 检测句子变更,立即重置状态 if (givenSentence != _currentSentence) { _currentSentence = givenSentence; _position = 0; textArea.text = ""; _writeCounter = 0f; } if (_writeCounter < writeOutDelay) { _writeCounter += Time.deltaTime; return; } if (_position >= givenSentence.Length) { writeOutSentences.writeNewSentence = false; writeOutSentences.interactText.textForInteraction = givenSentence; writeOutSentences.ableToWriteInto = true; _position = 0; return; } textArea.text += givenSentence[_position++]; writeOutSentences.ableToWriteInto = false; _writeCounter = 0f; } // 重置状态,解决Prefab复用残留 private void OnEnable() { _currentSentence = ""; _position = 0; _writeCounter = 0f; if(textArea != null) textArea.text = ""; } }
2. 优化WriteOutSentences赋值逻辑
private void Update() { if (!interacting || !writeNewSentence) { return; } if (rowIndex < _numberOfSentences) { // 仅在句子不同时赋值,避免持续覆盖 if(writeText.givenSentence != _sentenceList[rowIndex]) { writeText.givenSentence = _sentenceList[rowIndex]; } } else { writing.controlWordsProlog.canMove = true; Destroy(gameObject); } }
3. 调整rowIndex递增顺序
if (writing.ReturnText().Equals(textForInteraction)) { writing.ClearText(); textArea.text = ""; // 先递增索引再标记新句子,避免逻辑混乱 writeOutSentences.rowIndex++; writeOutSentences.writeNewSentence = true; }
内容的提问来源于stack exchange,提问作者LoadingError404
相关产品推荐
相关产品推荐

