クラスメモPart3-1
今回はRPG風のゲームを簡単ながら作りたいかな、と考えているので、次はMapで。
とりあえず、典型的なやつを一回作りたいので、行き当たりばったりでやってみる。
マップを作るので、マップチップの性質を列挙型に定義する。
#include "Array2D.h" //宣言だけではだめで、インクルードする必要がある。 class Map { public: Map(const char* filename); ~Map(); int getHeight(); int getWidth(); void Show(); private: //列挙型の値は int 型、unsigned int 型の変数に代入することができる //つまり /* Object o = OBJ_FLOOR; int a = o; //OK unsigned b = o; //OK */ //が可能 //unsigned int : 0 〜 65535 //int : -32768 〜 32767 enum Object { //列挙子の値はint型 OBJ_WALL =(0), OBJ_FLOOR =(1<<0), OBJ_EQUIP = (1<<1), }; int mHeight; int mWidth; Array2D<Object> mStageData; }; //ファイルから読み込むようにした。
この時、列挙型Objectは0,1,2しか取りえないので、たとえば、
「壁にアイテムが埋まっている」
みたいなのをこのままでは表現できない。
一つの方法としては、列挙型にありうる可能性のものをすべて書いておくという方法がある。
enum Object { //列挙子の値はint型 OBJ_WALL =(0), OBJ_FLOOR =(1<<0), OBJ_EQUIP = (1<<1), OBJ_EQUIP_ON_WALL = (1<<2) };
こうすると、もっと複雑になってしまうとき、「この状態は何て名前の列挙子にしたんだろうか」といちいち参照しなければ
ならなくなってしまう。「壁にアイテムが埋まっているけど、実は罠がある」みたいなのは3つの複合系と考えられるが、
とてもじゃないが記述しきれない。
一つの解決法としては、
enum Object { //列挙子の値はint型 OBJ_WALL =(0), OBJ_FLOOR =(1<<0), OBJ_EQUIP = (1<<1), }; unsigned mFlag; //ここにObjectの列挙子を突っ込む int mHeight; int mWidth; Array2D<unsigned> mStageData;
と書いてしまうという方法だ。しかしながら、unsignedをtypenameにしているので、unsigned型ならなんでも好き勝手に
値を格納できてしまう。(何とかして、「これはObject型の値を含んでいるんだよ。」と知らせたい。
そこで
unsignedではなくて、ObjectとmFlagを構造体として一つにまとめ、その構造体によって、Array2Dを動かそう.
#include "Array2D.h" //宣言だけではだめで、インクルードする必要がある。 class Map { public: Map(const char* filename); ~Map(); int getHeight(); int getWidth(); void Show(); private: //これをcpp側に書くとエラーになる。(たぶん、変数の定義しかしていないので)enumと同じように内部に書く必要がある? struct FlagOpr { enum Object { //列挙子の値はint型 OBJ_WALL =(0), OBJ_FLOOR =(1<<0), OBJ_EQUIP = (1<<1), }; unsigned flags; //これで列挙子のフラグが排他的でなくなる。 }; int mHeight; int mWidth; Array2D<FlagOpr> mStageData; };
これでよさげ。
あとは、フラグを動かせるような関数を作っておけば、可読性が増しそうだ.C++ではstructにも関数は置けるが、structはやめてclass
で定義しよう。(そうすれば、cpp側に処理を記述でき、ヘッダファイルに書かなくて済むというメリットもある。)
ほかのやり方としては、上塗りするという方法がある。
下-------------------------------上
床 壁、森、池など 家 アイテム 人
ごとにそれぞれクラスを作り、順々に上塗りする。
今のところ、マップチップの種類を2,3種類に限定しているので、この方法は後でする。