2017-08-29 96 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