我应该在哪里存储游戏的纹理? [英] Where should I store textures for a game?

查看:106
本文介绍了我应该在哪里存储游戏的纹理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用C ++在SFML中创建游戏,我想知道:纹理位置的最佳做法是什么?我应该将其存储在我的项目中吗?还是我的可执行文件?甚至在文档"文件夹中?从理论上讲,当游戏发行时,最有效的是什么,因为它将不仅包含项目,还包含其编译和构建版本?

I am currently creating a game in SFML using C++ and I'm wondering: what is good practise for a location for textures? Should I store it with my project? Or my executable? Or even in something like the Documents folder? What would be the most efficient when the game would theoretically be released, as it will not simply include the project but rather a compiled and build version of it?

推荐答案

大多数常见游戏发行版的纹理都在Media文件夹或类似文件夹中. 在该文件夹内还放置了声音,音乐和其他内容,通常放置在单独的文件夹中.

Most common game releases have their textures inside a Media folder or similar. Inside that folder are also placed sounds, music, and other content, tipically into separate folders.

它们不能成为可执行文件的一部分(据我所知).更重要的是如何在代码中管理那些纹理,这应该是一种有效的方法. 如果您有兴趣,我已经添加了有关如何执行此操作的说明.

They can't be part of the executable (as far as I know). More important is how do you manage those textures inside your code, it should be an efficient way. I've added an explanation about how to do that, if you're interested.

根据我自己制作一些小型电子游戏的经验,我发现最好使用资源持有者.这是任何重载资源(纹理,音乐,声音甚至字体)的通用容器.

From my own experience making some small videogames, I found better to use a Resource Holder. This is a generic container for any heavy resource (textures, music, sounds or even fonts).

其背后的主要思想是拥有一个映射,该映射将键(ID)与资源相关联. 您可能想存储各种资源,所以最好创建一个通用类.

The main idea behind this is to have a map which relates a key (an ID) with a resource. As you may want to store diferent kinds of resources, it's better to make a generic class.

基本实现:

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分开,但是我合并了它们,以避免发布(甚至更长的帖子).

I normally prefer to keep separate .hpp and .cpp, but I merged them to avoid a (even) longer post.

为使内容整洁有用,最好使用 Resource Identifier 标头文件,您可以在其中声明资源持有者的类型以及资源标识符.

To keep things clean and useful, it's a good practice to have Resource Identifier header file, where you can declare types for your resource holders, and your resource identifiers too.

// 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类的类(只要您的应用程序正在运行,该类就会被加载),您可以这样做:

As an example of use, if you have something like a Game class (a class that will be loaded as long as your application is running), you can do like this:

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类,该类将这些指针保存并分组为一个类,并使用该上下文作为所有将要使用的类的参数(即使是复制,因为它是一个轻量级的类).需要资源:

The key with this approach is to have your holders inside an always loaded class, and pass your holders as pointers or references. Another good way to do that is to have a Context class, which holds and group those pointers into only one class, and use that context as a parameter (even by copy, because it's a light class) of all your classes that will need a resource:

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游戏开发,此实现的来源.

You can find more info about this here: SFML Game Development, source of this implementation.

这篇关于我应该在哪里存储游戏的纹理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆