You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
    }
}

问题根源与修复方案

核心问题

  1. 多帧同步冲突:WriteOutSentences.Update持续给givenSentence赋值,而WriteTextProlog切换句子时未及时重置文本区域和位置变量,导致首字符复用上一句的状态。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 05:35:57