绘制到屏幕时字符串末尾的奇怪符号
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 行代码。
我正在开发一款带有对话框的游戏,在您阅读时会显示文本,就像在 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 行代码。