読者です 読者をやめる 読者になる 読者になる

本当にゲームプログラミング等における画像などリソースの管理がわからないので考えてみた

ゲームプログラミング等における画像などリソースの管理がわからない - TXT.TXT

の続き。ワカリマセーンワカリマセーン

 

で、

前回あげた方法の何が自分的に気に食わないかというと、自分では必要ない画像を自分が使うクラスが必要らしいということで読み込まされているということ

 

例えばStageというクラスがあったとしてStageがEnemy1~Enemy4というクラスを使うとする。Enemyは複数の画像を必要としている が、ゲーム中バリバリなアクションシーンで読み込むととても具合が悪いのであらかじめ読み込む必要がある。その「あらかじめ」をStageが担当するとする。さするとStageはこうなる

class Stage{

 public:

 Stage(){

 LoadGraphs{

  Enemy1_0.png,

  Enemy1_1.png,

  Enemy1_2.png,

  Enemy2_1.png,/*以下略*/}

 }

};

素晴らしきかな初期化リスト。しかしてそれでも醜い。もしもEnemyが増えたら。もしもEnemyが必要な画像が変わったら。そのもしももしもは恐らくやってくるであろう

 

じゃあどうすればいいかというとEnemyが必要なリソースをStageに文字列でもコマンドでもインタプリタでもどんな方法でもいいので教える関数を持てばよい

そしてStage自身も教える関数を持てばさらに前段階で読み込むことも可能になる

やったね問題解決だ

 

じゃあとりあえず実装にTemplateMethodパターンで、とはいけない

TemplateMethod パターンを使うにはとりあえずクラスをインスタンス化しなければならないが、Enemyをインスタンス化するときはすなわち画像ファイルが必要とするときである。仮に画像がなくてもプログラムが止まらないにしてもわざわざインスタンス化するのは馬鹿馬鹿しいのでEnemyインスタンス化より前に何とかしたい

よってstaticな関数が必要になるがstatic virtualという機能はC++に存在しないので(よく使うvitualを用いた)TemplateMethodは使えない

しかしstatic関数というアイデアは悪くないので使う

class Enemy1{
public:
    static ResorceInfoList Resorce(){ return{"a.jpg","b.mmd"}; }
};

Enemy2以降もこんな感じか

 

で、こんなクラスを作る

template<class ...UseType>
struct ResorceClasses{
    static std::vector<std::string> Resorce();


    template<class T,class ...Arg>
   static std::unique_ptr<T> Make(Arg&&...arg);
};

ResorceはUseType::Resorceの集合和を返す

MakeはTがUseTypeならばmake_uniqueと同じ働きをする。UseTypeでないならばコンパイルエラーを起こす

Stageクラスはこの型、というより関数集合を用いていろいろする

class Stage{

    using RC = ResorceClasses<Enemy1, Enemy2, Enemy3>;
    auto x=RC::Resorce();
 void Func(){
  auto x=RC::Make<Enemy1>();//つくったり
  Load(RC::Resorce());//読み込んだり
 }
}

StageがResorce関数を作ればさらに上に仕事を投げることも可能

 

しかしてこの方法、現時点で判明してる問題がある。今回Stageが使うリソース読み込みが必要なクラスはEnemyクラス3個だったからよかったがこれが100,200あると……

100,200のテンプレート引数を持ったResorceClassesが誕生する。可変長テンプレート引数パウヮーでごり押し

幸いResorceClassesもResorce関数を持っているので何回かに分けて一つの大きなクラスにすれば見た目はましになるが、ましになるのは見た目だけで結局書く量は変わらない(むしろ増える)

 

はたして画像読み込みが楽になったか……と言われると若干疑問が残るがそれでも歯痒さがなくなった分、それで良しということにしたい。良しとしよう。よし