从官方SFML教程中,白盒问题: -
"当您设置精灵的纹理时,它在内部所做的只是存储指向纹理实例的指针。因此,如果纹理被破坏或移动到内存中的其他位置,则精灵最终会出现无效的纹理指针。"因此,可以看到没有纹理的精灵。
我有一个名为世界的课程。在这个类中,我创建了一个名为 level 的二维整数数组,并且一个名为blocks 的Block类型的向量。现在我想存储' Block'每当level [i] [j] = 1时,向量内的对象。
'世界'的头文件类: - 的
#ifndef WORLD_H
#define WORLD_H
#include <vector>
#include "Block.h"
#include "Grass.h"
#include <SFML/Graphics.hpp>
using namespace std;
class World
{
public:
World();
void draw(sf::RenderWindow *window);
vector<Block> blocks;
private:
int level[12][16];
int wd;
int hi;
};
#endif // WORLD_H
世界&#39;&#39; cpp文件class : -
#include "World.h"
#include "Grass.h"
#include "Block.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
World::World() : level{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
}
{
wd = 16;
hi = 12;
int count = 1;
//make a 'Block' object and pass it in the vector when level[ i ][ j ] = 1.
for(int i = 0; i<hi; i++)
{
for(int j = 0; j<wd; j++)
{
if(level[i][j] == 1)
{
Block block(j*50, i*50);
blocks.push_back(block);
}
}
}
}
void World::draw(sf::RenderWindow *window)
{
for(unsigned int i = 0; i<blocks.size(); i++)
{
blocks[i].draw(window);
}
}
&#39; Block&#39; class有两个成员 - sf :: Texture blockT 和 sf :: Sprite block 。它还有一个draw(RenderWindow * window)方法。这就是&#39; Block&#39;上课: -
块类的头文件
#ifndef BLOCK_H
#define BLOCK_H
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
class Block
{
public:
Block(float x, float y);
void draw(sf::RenderWindow *window);
private:
sf::Texture blockT;
sf::Sprite block;
};
#endif // BLOCK_H
cpp文件&#39;阻止&#39;类
#include "Block.h"
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
Block::Block(float px, float py)
{
if(!(blockT.loadFromFile("textures/block.png")))
{
cout<<"Could not load block texture."<<endl;
}
block.setTexture(blockT);
block.setPosition(sf::Vector2f(px, py));
cout<<px<<endl;
cout<<py<<endl;
}
void Block::draw(sf::RenderWindow *window)
{
window->draw(block);
}
当我运行程序时,代替块,只显示白框。我不明白纹理是如何被破坏的。这是输出的样子: -
正如你所看到的,白色的地方是精灵,每个都是50 * 50,没有任何纹理。
答案 0 :(得分:1)
您应该自定义块的复制构造,以便更新纹理指针,如:
base_url()
当Block::Block(const Block& other)
: blockT(other.blockT), block(other.block)
{
block.setTexture(blockT);
}
中的push_back()
强制调整大小时,将使用该值,并且在旧元素被“破坏”和解除分配之前,旧元素的新分配的较大缓冲区元素是复制构造的。
支持相同类型的分配更新,即vector
,这是一个好主意。
关于你的“这样就会看到没有纹理的精灵。” - 这种行为更可能是 undefined ,因为你'有效地跟随指向已释放内存的指针,该指针可能随时被新内容损坏,并且恰好表现为测试中当前缺少纹理,但在一些次要代码更改后可能会崩溃并在其他优化级别刻录,在另一个编译器或操作系统等..
答案 1 :(得分:0)
你有一个Block类存储它自己的sf :: Texture实例的解决方案会让你在内存中有重复的纹理副本。当您根据Tony D's答案处理您的Block对象时,它还会要求您学习并遵循三条规则。
更简单的解决方案是为sf :: Textures提供单独的std :: filenames映射,您可以在其中加载一次所需的纹理,并在任何需要的地方检索它们。
// Have one of these, maybe as a member of your World class?
std::map<std::string,sf::Texture> textures;
// load your textures into it ...
然后在你的Block类......
class Block
{
public:
// constructor now takes a reference to a texture map ...
Block(float x, float y,std::map<std::string,sf::Texture>& textures);
在实现中,您可以通过文件名检索所需的纹理,并使用setTexture将其指定给精灵。