我正在SFML2中编写一个简单的游戏,它基于等距的瓷砖。地图中的每个图块都由Tile类表示。该类包含sf :: Sprite对象和draw()
函数,该函数应该在屏幕上绘制精灵。问题是调用window.draw()
会导致分段错误。我已经读过它通常是由相关的sf :: Texture指针无效引起的,但我已经检查过了,情况并非如此。
(使用ResourceManager<sf::Texture>
对象将纹理引用传递给Tile构造函数)
tile.hpp:
#pragma once
#include <SFML/Graphics.hpp>
#include "resource_manager.hpp"
class Tile
{
public:
Tile(const sf::Texture& texture);
void draw(sf::RenderWindow& window, const float dt);
private:
sf::Sprite _sprite;
};
tile.cpp:
#include "tile.hpp"
Tile::Tile(const sf::Texture& texture)
{
_sprite.setTexture(texture);
}
void Tile::draw(sf::RenderWindow& window, const float dt)
{
std::cout << _sprite.getTexture()->getSize().x << std::endl; //Texture pointer works fine
window.draw(_sprite); //Segmentation Fault here
}
map.hpp:
#pragma once
#include <vector>
#include <SFML/Graphics.hpp>
#include "resource_holder.hpp"
#include "tile.hpp"
class Map
{
public:
Map(ResourceHolder& resources, int width, int height);
void draw(sf::RenderWindow& window, const float dt);
private:
ResourceHolder& _resources;
int _width, _height;
std::vector<Tile> _tiles;
};
map.cpp:
#include "map.hpp"
#include <iostream>
Map::Map(ResourceHolder& resources, int width, int height)
: _resources(resources), _width(width), _height(height)
{
_tiles.reserve(width * height);
for(int y = 0; y < _height; ++y)
{
for(int x = 0; x < _width; ++x)
{
_tiles[x + y * _width] = Tile(_resources.textures["groundTile_NE"]);
}
}
}
void Map::draw(sf::RenderWindow& window, const float dt)
{
for(int x = 0; x < _width; ++x)
{
for(int y = 0; y < _height; ++y)
{
_tiles[x + y * _width].draw(window, dt);
}
}
}
resource_manager.hpp:
#pragma once
#include <unordered_map>
#include <iostream>
template<typename Resource>
class ResourceManager
{
public:
ResourceManager(const std::string& directory, const std::string& extension)
: _directory("assets/" + directory + "/"), _extension("." + extension)
{}
Resource& operator[](const std::string& name)
{
return get(name);
}
Resource& get(const std::string& name)
{
if(!exists(name))
load(name);
return _resources.at(name);
}
bool exists(const std::string& name) const
{
return _resources.find(name) != _resources.end();
}
void load(const std::string& name)
{
Resource res;
if(!res.loadFromFile(_directory + name + _extension))
{
res.loadFromFile(_directory + "_fail_" + _extension);
}
_resources.insert({name, res});
}
private:
const sf::String _directory;
const sf::String _extension;
std::unordered_map<std::string, Resource> _resources;
};
答案 0 :(得分:2)
从SFML源代码(Graphics/Texture.cpp)中,析构函数导致OpenGL纹理缓冲区被删除:
Texture::~Texture()
{
// Destroy the OpenGL texture
if (m_texture)
{
TransientContextLock lock;
GLuint texture = static_cast<GLuint>(m_texture);
glCheck(glDeleteTextures(1, &texture));
}
}
在load
方法中,您在堆栈上分配对象res
。这意味着当方法返回时,将在Resource
对象上调用res
的析构函数。您的OpenGL句柄已删除,但仍存储在您插入res
的{{1}}的副本中。
要解决此问题,请改为存储资源类的指针:
_resources
但是当你销毁std::unordered_map<std::string, Resource*> _resources;
...
void load(const std::string& name)
{
Resource* res = new Resource();
if (!res->loadFromFile(_directory + name + _extension))
{
res->loadFromFile(_directory + "_fail_" + _extension);
}
_resources.insert({name, res});
}
Resource* operator[](const std::string& name)
{
return get(name);
}
Resource* get(const std::string& name)
{
if (!exists(name))
load(name); // or return nullptr
return _resources.at(name);
}
对象时,你还需要销毁这些指针:
ResourceManager
注意:您可能想在~ResourceManager()
{
for (auto& pair : _resources)
delete pair.second;
}
中存储引用。但请参阅this link了解为什么那是不可能的。