如何正确地将精灵传递给std :: Vector而不破坏它们的纹理?

时间:2015-05-08 02:13:20

标签: c++ vector textures sprite sfml

从官方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);
}

当我运行程序时,代替块,只显示白框。我不明白纹理是如何被破坏的。这是输出的样子: -

messed up textures

正如你所看到的,白色的地方是精灵,每个都是50 * 50,没有任何纹理。

2 个答案:

答案 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将其指定给精灵。