c++ - 无法使用 RenderTexture 创建精灵
问题描述
我正在制作游戏,并且创建了一个类来存储地图。我有一个函数来创建一个单独的精灵,在它上面绘制了所有可见的地图。我使用了 RenderTexture,然后创建并返回了一个用它创建的精灵。然而,精灵是完全白色的。
这是地图生成和精灵绘制的代码
void Map::procedural_generate()
{
cout << "Starting the map generation" << endl;
int generation_max = m_size.x * m_size.y,
current_generation = 0;
vector<Decor> decor_vector;
m_decor_vector.clear();
const vector<Decor> const_vector
{
Decor(GRASS)
};
for (int i = 0; i < m_size.x; i++)
{
decor_vector.clear();
for (int j = 0; j < m_size.y; j++)
{
decor_vector.push_back(const_vector[GRASS]);
decor_vector[j].set_position(Vector2f(i * 32, j * 32));
current_generation++;
cout << "Generation : " << current_generation << '/' << generation_max << '\r';
}
m_decor_vector.push_back(decor_vector);
decor_vector.clear();
}
cout << "Map generation has ended" << endl;
}
Sprite Map::sprite()
{
RenderTexture map;
if (!map.create(WINDOW_WIDTH, WINDOW_HEIGTH))
cout << "Map : Unable to create the RenderTexture" << endl;
map.clear(Color::Green);
for (int i = 0; i < m_size.x; i++)
for (int j = 0; j < m_size.y; j++)
map.draw(m_decor_vector[i][j].sprite());
map.display();
Sprite sprite(map.getTexture());
return sprite;
}
问题似乎来自 map.draw 部分,因为如果我map.clear(Color::Red)
在双循环之前使用,精灵会保持白色,但如果我使用sprite.setColor(Color::Red)
,它可以工作。事实是装饰精灵并没有覆盖整个纹理(纹理是 1920x1080,精灵是 320x320),所以我不明白发生了什么。
这不是装饰精灵加载,如果我使用map.draw(Decor(GRASS))
精灵正确显示。
我尝试将指针用于const_vector
返回的精灵,但没有成功。
解决方案
使用 SFML 时的常见错误。
Sprite Map::sprite()
{
RenderTexture map;
// ...
Sprite sprite(map.getTexture());
return sprite;
}
map
是本地的。当函数结束时,map
被销毁。Sprite 将纹理map
作为浅拷贝,它只是指向纹理的指针,根据官方教程/文档:
白色方块问题 您成功加载了纹理,正确构建了一个精灵,并且……您现在在屏幕上看到的只是一个白色方块。发生了什么?
这是一个常见的错误。当您设置精灵的纹理时,它在内部所做的只是存储指向纹理实例的指针。因此,如果纹理被破坏或移动到内存中的其他位置,则精灵最终会得到一个无效的纹理指针。
因此,副本返回的精灵存储了悬空指针。这只是未定义的行为。
解决方案:您必须将带有纹理的精灵包装在某种可深度复制的类中。您不能依赖浅默认生成的复制操作。
这样的类可能如下所示:
class TexturedSprite {
public:
sf::Sprite sprite;
sf::Texture texture;
TexturedSprite() {
init(); // load texture
}
void init() {
// load texture
texture.loadFromFile("texture1.png");
sprite.setTexture(texture);
sprite.setPosition(0,0);
}
TexturedSprite(const TexturedSprite& theOther) {
texture = theOther.texture; // deep copy
sprite.setTexture(texture);
}
TexturedSprite& operator=(const TexturedSprite& theOther) {
if (this == &theOther)
return *this;
texture = theOther.texture; // deep copy
sprite.setTexture(texture);
return *this;
}
};
然后是代码:
TexturedSprite fooMain;
{
TexturedSprite foo; // local
fooMain = foo;
} // foo is destroyed, but = did deep copy of texture
是安全的。
推荐阅读
- android - Requery for Android 会自动生成类吗?
- django - 如何在 Django 中删除 ForeignKey 约束?
- typescript - 在动态 import() 中使用完整 URL
- button - 我如何在pyqt5中绑定qtquick按钮控件
- vue.js - 切换页面时Vue路由器挂载两次
- javascript - Service Worker 推送事件数据为空
- c# - 检查字符串是否包含匹配的字符串属性
- scheme - 在 script-fu (TinyScheme) 中连接字符串和变量
- php - 图像上传和显示
- asp.net-mvc-5 - 在生产环境中的 ASP.NET MVC 5 中的 URL 中隐藏项目名称