2017-08-29 94 views
0

我正在写基于等轴测图的SFML2中的一个简单的游戏。地图中的每个图块都由Tile类表示。该类包含sf :: Sprite对象和draw()函数,该函数应该在屏幕上绘制精灵。问题是调用window.draw()会导致分段错误。我读过它通常是由相关的sf :: Texture指针无效而引起的,但我已经检查过,但事实并非如此。绘制精灵导致分割错误

(纹理参考被传递给使用ResourceManager<sf::Texture>对象平铺构造函数)

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

@Eddge它确实返回指针,我的错误 – Hadenir

+0

@meowgoesthedog资源是一个模板类型名。这是sf ::纹理在这种情况下 – Hadenir

+0

oops原谅我,我没有看到模板声明。评论已删除 – meowgoesthedog

回答

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句柄被删除,但仍保存在您插入_resources副本res中。

要解决这个问题,店里指针的资源类,而不是

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

注意:您可能会试图在_resources中储存参考文献。但请参阅this link为什么这是不可能的。

+0

它解释了很多,谢谢。我基于我的经理这个代码:https://github.com/Hopson97/SFML-Game-Framework/blob/master/Source/ResourceManager/ResourceManager.h我不知道为什么它为他工作,但不是在我的情况。 – Hadenir

+0

@Hadenir嗯,不要过分怀疑一位知名博客,但你确定它对他有用吗?我的意思是,你的代码(和他的)*编译*很好,但是我无法找到他实际上在库中任何地方使用*'ResourceManager/Holder'的地方。也许我们应该亲自问这个人? – meowgoesthedog

+0

我在想同样的事情,但在视频中,他做的纹理效果很好。尽管如此,感谢帮助meowgoesthedog! – Hadenir