【问题标题】:Weird symbol at the end of strings when drawn to the screen绘制到屏幕上时字符串末尾的奇怪符号
【发布时间】:2017-08-18 15:54:00
【问题描述】:

我正在开发一个带有对话框的游戏,当您阅读它时会显示文本,就像在 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 代码,通常使用起来很烦人。您是否考虑过使用std::istringstream 代替? en.cppreference.com/w/cpp/io/basic_istringstream当你从中读取一个字符串时,它将被空格分隔。
  • 可能是这样的:pastebin.com/fF1GZAJ2
  • @quetzalcoatl cout 行只写“成功!”因为算法完成后什么都没有发生。我检查了我刚才写的Node相等运算符,没有任何明显的错误,它只是返回position == otherNode.position
  • 好吧..所以假设while 永远不会中断并且 if(end) 中的return 永远不会返回,那么您怎么知道算法有效并且找到了解决方案?或者您实际上在控制台输出中看到了“成功”?
  • @quetzalcoatl 是的,我知道它完成的唯一方法是它是否输出“成功”,如果没有,它会无限期地继续。我也做了它,所以它不可能找到它正在寻找的东西,因为算法穿过墙壁。

标签: c++ string sfml


【解决方案1】:

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

strtok 是来自 C 的保留。它有它的用途,但它要求你离开 std::string 的舒适性,以适应 c 字符串的狂野和毛茸茸的世界以及动态分配或非标准 @987654321 @ 由 OP 使用。它也有潜在的失败案例,这些案例源于被编写为从更简单的时代处理更简单的问题。例如,所有strtoks 都使用相同的内部缓冲区。明显的线程影响已经用线程本地存储解决了,剩下的两个或多个并发strtoks 在一个线程中的问题用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.

【讨论】:

  • 1201ProgramAlarm 的回答对我有用,但我仍然想学习这个。它没有为我编译,basic_istringstream in(nText) 不起作用。你的代码是伪代码还是文字代码?
  • @Merle 尝试文字。显然我无法编译它,因为我没有TextRenderer。给我一点时间,看看我是否错过了什么愚蠢的事情。
  • 我没有提到需要额外的包括:#include &lt;sstream&gt;
  • 我忘记回复了,我让它工作了,它比使用 strtok 更干净和简单。谢谢!
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多