【问题标题】:How can I properly pass sprites to a std::Vector without destroying their texture?如何在不破坏纹理的情况下正确地将精灵传递给 std::Vector?
【发布时间】:2015-05-08 02:13:19
【问题描述】:

来自官方 SFML 教程,白盒问题:-

“当你设置一个精灵的纹理时,它在内部所做的只是存储一个指向纹理实例的指针。因此,如果纹理被破坏或移动到内存中的其他地方,精灵最终会得到一个无效的纹理指针。”因此将看到一个没有纹理的精灵。

我有一个名为 World 的课程。在这个类中,我创建了一个名为 level 的二维整数数组和一个名为 Block 的 Block 类型的向量。现在我想在 level[ i ][ j ] = 1 时将“块”对象存储在向量中。

'World' 类的头文件:-

#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

'World' 类的 cpp 文件 :-

#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);
    }
}

'Block' 类有两个成员 - sf::Texture blockTsf::Sprite block。它还有一个 draw(RenderWindow *window) 方法。这就是“块”类的制作方式:-

块类的头文件

#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

'Block' 类的 cpp 文件

#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 的精灵,没有任何纹理。

【问题讨论】:

标签: c++ vector textures sprite sfml


【解决方案1】:

您应该自定义块的复制构造,以便它更新纹理指针,例如:

Block::Block(const Block& other)
  : blockT(other.blockT), block(other.block)
{
    block.setTexture(blockT);
}

这将在vector 中的push_back() 强制调整大小时使用,并且新分配的较大缓冲区的元素在旧元素被“破坏”和释放之前从旧元素复制构造。

最好支持相同类型的分配更新,即operator=(const Block&amp; rhs)

关于您的“因此会看到一个没有纹理的精灵。” - 因为您的行为很可能是未定义 '有效地遵循指向已释放内存的指针,该指针可能随时被新内容破坏,并且恰好表现为当前测试中缺少纹理,但在一些小的代码更改后可能会在其他优化级别崩溃和烧毁,在另一个编译器或操作系统等上。

【讨论】:

    【解决方案2】:

    拥有一个存储自己的 sf::Texture 实例的 Block 类的解决方案将导致您在内存中挂起重复的纹理副本。当您按照Tony D's 的回答处理您的 Block 对象时,还需要您学习并遵循三原则。

    更简单的解决方案是有一个单独的文件名 std::map 到 sf::Textures,您可以将所需的纹理加载到其中一次,然后在任何需要它们的地方检索。

    // 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 将其分配给精灵。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-04
      相关资源
      最近更新 更多