Большинство распространенных выпусков игр имеют свои текстуры внутри папки Media или аналогичной.
Внутри этой папки также помещены звуки, музыка и другое содержимое, обычно в отдельные папки.
Они не могут быть частью исполняемого файла (насколько я знаю). Более важно то, как вы управляете этими текстурами внутри вашего кода, это должно быть эффективным способом.
Я добавил объяснение о том, как это сделать, если вам интересно.
TL DR
Исходя из собственного опыта создания небольших видеоигр, я обнаружил, что лучше использовать Resource Holder . Это универсальный контейнер для любого тяжелого ресурса (текстуры, музыка, звуки или даже шрифты).
Основная идея заключается в том, чтобы иметь карту, которая связывает ключ (ID) с ресурсом.
Поскольку вы можете хранить разные виды ресурсов, лучше создать общий класс.
Базовая реализация:
template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
void load(Identifier id, const std::string& filename){
// Create and load resource
std::unique_ptr<Resource> resource(new Resource());
if (!resource->loadFromFile(filename))
throw std::runtime_error("ResourceHolder::load - Failed to load " + filename);
// If loading successful, insert resource to map
insertResource(id, std::move(resource));
}
Resource& get(Identifier id){
auto found = mResourceMap.find(id);
assert(found != mResourceMap.end());
return *found->second;
}
const Resource& get(Identifier id) const {
auto found = mResourceMap.find(id);
assert(found != mResourceMap.end());
return *found->second;
}
protected:
void insertResource(Identifier id, std::unique_ptr<Resource> resource){
// Insert and check success
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource)));
assert(inserted.second);
}
protected:
std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
};
Обычно я предпочитаю разделять .hpp
и .cpp
, но я объединил их, чтобы избежать (даже) более длинного поста.
Для поддержания чистоты и полезности рекомендуется иметь Идентификатор ресурса заголовочный файл, в котором вы можете объявлять типы для ваших владельцев ресурсов и ваши идентификаторы ресурсов.
// Forward declaration of SFML classes
namespace sf
{
class Texture;
// If you need, you can use other SFML classes into your holders the same way
//class Font;
//class SoundBuffer;
}
namespace Textures
{
enum ID
{
TitleScreen,
LoadingScreen,
GameOverScreen,
Title,
Controls,
GUI,
TileMap,
Player,
Enemy,
Key,
PlayerMods
};
}
// Forward declaration and a few type definitions
template <typename Resource, typename Identifier>
class ResourceHolder;
typedef ResourceHolder<sf::Texture, Textures::ID> TextureHolder;
//typedef ResourceHolder<sf::Font, Fonts::ID> FontHolder;
//typedef ResourceHolder<sf::SoundBuffer, Sounds::ID> SoundHolder;
В качестве примера использования, если у вас есть что-то вроде Game
класса (класс, который будет загружаться, пока ваше приложение работает), вы можете сделать так:
class Game {
public:
Game() :
_window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Game")
{
// EXAMPLES
//_fonts.load(Fonts::Main, FONTS_FOLDER + "font.ttf");
//_musics.load(Musics::Game, MUSIC_FOLDER + "main.ogg");
//_musics.get(Musics::Game).setLoop(true);
//_sounds.load(Sounds::Key, SOUNDS_FOLDER + "key.wav");
_textures.load(Textures::TitleScreen, TEXTURES_FOLDER + "titlescreen.png");
// More code ...
}
void run(){
// Your game loop: process inputs, update and render until you close
}
private:
void update(sf::Time dt){
// ...
}
void processInput(){
// ...
}
void render(){
_window.clear(sf::Color::Black);
// Here you can use your resources to draw
sf::Sprite sp(_textures.get(Textures::TitleScreen));
_window.draw(sp);
_window.display();
}
sf::RenderWindow _window;
TextureHolder _textures;
//FontHolder _fonts;
//SoundHolder _sounds;
};
Ключ с этим подходом - , чтобы ваши держатели были внутри всегда загруженного класса и передавать их как указатели или ссылки. Еще один хороший способ сделать это - иметь класс Context
, который содержит и группирует эти указатели только в один класс, и использует этот контекст в качестве параметра (даже путем копирования, потому что это легкий класс) всех ваших классов, которые будут нужен ресурс:
struct Context
{
Context(sf::RenderWindow& window, TextureHolder& textures, FontHolder& fonts, MusicHolder& musics, SoundHolder& sounds);
sf::RenderWindow* window;
TextureHolder* textures;
FontHolder* fonts;
MusicHolder* musics;
SoundHolder* sounds;
};
Вы можете найти больше информации об этом здесь: Разработка игр SFML , источник этой реализации.