绘制到屏幕时字符串末尾的奇怪符号

Weird symbol at the end of strings when drawn to the screen

我正在开发一款带有对话框的游戏,在您阅读时会显示文本,就像在 RPG 中一样。我让它工作了,但我的一个问题是当我将它绘制到屏幕上时,有一个奇怪的符号我没有输入而且不在键盘上。我在下面有一个 gif 来演示。

这是我的代码:

TextRenderer.h

#ifndef TEXTRENDERER_H
#define TEXTRENDERER_H
#include <SFML/Graphics.hpp>
#include <iostream>

using namespace sf;
using namespace std;

class TextRenderer {
    public:
        Texture *t;
        Sprite sprite;
        string currentString, fullString, eBeforeString;
        int currentWordNum, onTheLine;
        vector<string> words;
        Text drawableText;
        Font font;
        Clock charTime;
        TextRenderer();
        void update();
        void newText(string nText);
};

#endif // TEXTRENDERER_H

TextRenderer.cpp

#include "TextRenderer.h"
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstring>

using namespace sf;
using namespace std;

TextRenderer::TextRenderer() {
    t = new Texture;
    t->loadFromFile("data/images/talkScreen.png");
    sprite.setTexture(*t);
    sprite.setOrigin(sprite.getGlobalBounds().width/2, 0);
    sprite.setScale(4, 4);
    font.loadFromFile("data/fonts/VCR_OSD_MONO_1.001.ttf");
    drawableText.setFont(font);
    drawableText.setFillColor(Color::White);
    drawableText.setCharacterSize(30);
    currentWordNum = 0; /// Initializing variables
    currentString = "";
    eBeforeString = "";
}

void TextRenderer::update() {
    /// If the current word number (spot in the words vector) is less than
    /// the size of the words vector
    if (currentWordNum < words.size()) {
        if (currentString.length() < words.at(currentWordNum).length()) {
            if (charTime.getElapsedTime().asSeconds() >= 0.02) {
                currentString = words.at(currentWordNum).substr(0, currentString.length() + 1);
                charTime.restart();
                onTheLine += 1;
            }
        } else if (currentString == words.at(currentWordNum)) {
            /// If you just finished typing a word
            if (charTime.getElapsedTime().asSeconds() >= 0.02) {
                eBeforeString += currentString + " ";
                currentString = "";
                currentWordNum += 1;
                onTheLine += 1;
                if (currentWordNum != words.size()) {
                    if (onTheLine + words.at(currentWordNum).length() >= 53) {
                        eBeforeString += "\n";
                        onTheLine = 0;
                    }
                }
            }
        }
    }
    drawableText.setString(eBeforeString + currentString);
}

void TextRenderer::newText(string nText) {
    fullString = nText;
    /// Breaking the string into 'words' which I add to a vector
    char eStr[fullString.length()];
    for (unsigned i = 0; i < fullString.size(); i++) {
        eStr[i] = fullString.at(i);
    }
    char *spt = strtok(eStr, " ");
    while (spt != NULL) {
        words.push_back(spt);
        spt = strtok(NULL, " ");
    }
    currentString = "";
    eBeforeString = "";
    currentWordNum = 0;
    onTheLine = 0;
    drawableText.setString(currentString);
    drawableText.setPosition(sprite.getPosition().x + 20 - sprite.getGlobalBounds().width/2, sprite.getPosition().y + 10);
    charTime.restart();
}

而在 main.cpp 中,我只是调用

textScreen.newText("Look at the symbol at the very end of this string on the other side of this period .");

strtok 期望您传递给它的字符串是 C 风格的字符串并以 NUL ('[=11=]') 字符结尾。您传递给它的字符串 (eStr) 没有,因此对 strtok 的最后一次调用超过了数组的末尾,导致未定义的行为。

您需要在 eStr 的大小上添加一个额外的字符,并将最后一个字符设置为 '[=11=]'(或 0)。

1201ProgramAlarm的回答解决了眼前的问题,但我有不同的看法

strtok 是 C 的遗留物。它有其用途,但它要求您离开 std::string 的舒适区,转而使用 C 字符串的狂野和毛茸茸的世界,动态分配或OP 使用的非标准 Variable Length Array。它也有潜在的失败案例,这些案例源于为处理更简单的时代的更简单问题而编写的。例如,所有 strtok 都使用相同的内部缓冲区。明显的线程影响已经用线程本地存储解决了,一个线程中两个或多个并发strtok的剩余问题用strtok_r(可重入strtok)解决了,但既然我们是用 C++ 编码,我们不妨用 C++ 流来处理这个问题。

我可以建议

void TextRenderer::newText(string nText) {
    fullString = nText;

// replacement starts here
    istringstream in(nText);
    string word; 
    while (in >> word) {
        words.push_back(word);
    }
//end replacement

    currentString = "";
    eBeforeString = "";
    currentWordNum = 0;
    onTheLine = 0;
    drawableText.setString(currentString);
    drawableText.setPosition(sprite.getPosition().x + 20 - sprite.getGlobalBounds().width/2, sprite.getPosition().y + 10);
    charTime.restart();
}

这完全消除了对 eStr 的需要(这让我很痛苦,因为我喜欢找蛋)并将代码减少到易于阅读的 5 行代码。

Documentation on istringstream.