Siv3Dでリソースファイルをまとめてexeに埋め込むワークフロー


この記事は Siv3D Advent Calendar 2016 15日目の記事です。

画像や音声、テキストファイル、フォントファイル等のリソースファイルをユーザから隠蔽したい場合、Siv3Dではリソースファイルを実行ファイルに埋め込むことができます。

しかし、製作中のプログラムに追加のリソースがあるたびにResource.rcにファイル名を記述するのは面倒です。
ファイルパスもリソース番号としてしか扱えないし…。

そこで、複数のファイルをひとつにまとめるアーカイブ機能を使って、ファイル埋め込みの手間を減らしましょう。

1.アーカイブファイルの作成

アーカイブファイルの作成方法はこちらで解説の通り。
Siv3D/Reference-JP/アーカイブファイル

アーカイブファイルはフォルダ単位でアーカイブ化できるので、必要なリソースファイルを全てひとつのフォルダにまとめます。
(筆者はテクスチャならテクスチャ、サウンドならサウンドごとに分けています)

実装中のプログラムでいちいちアーカイブファイルを作成するのは煩雑なので、以下のようなexeを作ってしまいましょう。

main.cpp
# include <Siv3D.hpp>

void Main()
{
    Console::Open();
    Window::Minimize();

    if (CommandLine::Get().size() < 3){
        std::wcout << L"参照パスとファイル名をコマンドライン入力で指定してください。" << std::endl;
    }
    else {
        Archive::Create(CommandLine::Get()[1], CommandLine::Get()[2]);
        std::wcout << L"Make Archive! \"" + CommandLine::Get()[2] + L"\" From \"" + CommandLine::Get()[1] + L"\"" << std::endl;
        std::wcout << L"FileSize: " + Format(FileSystem::FileSize(CommandLine::Get()[2])) + L"byte" << std::endl;
    }
    std::wcout << L"Enterキーを押して終了してください。" << std::endl;
    getchar();
}

あとはこのexeに、リソースフォルダのパスとアーカイブファイルのファイル名を渡して実行すればOKです。
バッチで起動してもいいですが、ショートカットでも起動できます。

というふうにショートカットを作成すると、Textureフォルダの中身をまとめたTextureAcv.s3aファイルが作成されます。
フォルダ・アーカイブファイルの指定は相対パスで行っています。

リソースフォルダにこのショートカットを置いておけば、ファイル追加→ショートカット実行でアーカイブファイルが作成されてお手軽です。
(アーカイブファイルにショートカットも含まれてしまうので、配布版を作る前には別のところに移したほうがいいです)

2.アーカイブファイルの埋め込み

手順1で作ったアーカイブファイルを埋め込みます。
埋め込みについてはこちらで解説の通り。
Siv3D/Reference-JP/ファイルの埋め込み

特にひねることなく、そのままResource.rcに記述します。
読み込みもそのまま。

Resource.rc
1010    FILE    "TextureAcv.s3a"
1020    FILE    "SoundAcv.s3a"
main.cpp
void Main()
{   
    FileArchive textureAcv(L"/1010");

    Texture playerTexture(textureAcv.load(L"chr/player.png"))
    Texture buttonTexture(textureAcv.load(L"menu/button.png"))

    FileArchive soundAcv(L"/1020"); 

    Sound jumpSound(soundAcv.load(L"chr/jump.wav"));
    Sound selectSound(soundAcv.load(L"menu/select.wav"));
}

アーカイブファイルを再度作成し直した場合も、Resource.rcの更新は不要です。

3.ビルドせずにアーカイブファイルを読み込みたい場合

ただしこのままでは、アーカイブファイルの更新後、ビルドしなければexeにアーカイブファイルの更新が反映されません。

リソース調整のたびにビルドするのは不便です。
アーカイブファイルが所定の場所に存在する場合はそちらを、存在しない場合はexe埋め込みのアーカイブファイルを読むようにしましょう。

main.cpp
void Main()
{   
    FileArchive textureAcv;

    if(FileSystem::Exists(L"TextureAcv.s3a")){
        textureAcv = FileArchive(L"TextureAcv.s3a");
    }else{
        textureAcv = FileArchive(L"/1010");
    }

    Texture playerTexture(textureAcv.load(L"chr/player.png"))
    Texture buttonTexture(textureAcv.load(L"menu/button.png"))
}

これで、ビルドせずにアーカイブファイルを読み込めるようになりました。

ただしこのまま配布してしまうと、不正なファイルを読み込んでしまう恐れがあります。
配布時には最初からexe埋め込みのアーカイブファイルを読み込むように修正しましょう。

まとめ

実行ファイルへのファイル埋め込みはそのまま使用すると色々と手間です。
アーカイブファイル機能を利用して効率化しましょう。
アーカイブ作成用の実行ファイルを作っておくと更に便利です。