今回はステートパターンを勉強してみました。
ステートパターンとは-
継承を利用してランタイムで状態を変化させるデザインパターンの一つ。
メインに書くプログラムの量が少なくなり見た目もよくなる。
つまり、ゲームの状態、例えばミニゲームを沢山入れたいゲームなんかはこのステートパターンでゲームの中身を変えればメインにべた書きせずに済むし、わかりやすくなるのでは?と思いました。
ということでDXlibを使って試してみよう。
今回は状態移行がわかるように表示した文字を上下キーで入れ替えれるようにした。
まず初めに 状態の基底クラスを作る。今回は GameStateP としました。
----------------------------------------------------------------------
class GameStateP
{
public:
virtual char* Chara_name()=0;//キャラクター名を返す
virtual char* Game_type()=0;//ゲームの種類を返す
};
----------------------------------------------------------------------
これだけですね。
次に 派生クラスを二つ作ります。
----------------------------------------------------------------------
#include"../../GameStateP.h"
class Bananashot :public GameStateP
{
public:
char* Chara_name()override { return "BANANAだよ"; };
char* Game_type()override { return "シューティングだよ";};
};
----------------------------------------------------------------------
----------------------------------------------------------------------
#include <string>
#include"../../GameStateP.h"
class Chomoshot :public GameStateP
{
public:
char* Chara_name()override { return "Chomoranmaだよ"; };
char* Game_type()override{ return "野球盤だよ"};
};
----------------------------------------------------------------------
とりあえずバナナとチョモランマ。どちらもGameStatePを基底とする派生クラスです。
これによりGameStateP*型にどちらもインスタンス化ができるようになりました。
次は GameStateP を所持しを管理する Gametypeクラス を作ります。
----------------------------------------------------------------------
class GameStateP;
class Gametype
{
public:
Gametype();
~Gametype();
static Gametype* GetIns()
{
static Gametype* game = new Gametype;
return game;
}
char* Get_Char()const;//キャラクターの表示
char* Get_type()const;//ゲームの種類の表示
void banana();//バナナに切り替え
void chomo();//チョモランマに切り替え
private:
void Chang_Game(GameStateP* State);//デリートと切り替えをする
GameStateP* gameState;
};
----------------------------------------------------------------------
----------------------------------------------------------------------
#include "Gametype.h"
#include"bananashot.h"
#include"Chomoranshot.h"
Gametype::Gametype():
gameState(new Bananashot())
{
}
Gametype::~Gametype()
{
}
char* Gametype::Get_Char() const
{
return gameState->Chara_name();
}
char* Gametype::Get_type()const
{
return gameState->Game_type();
}
void Gametype::banana()
{
this->Chang_Game(new Bananashot());
}
void Gametype::chomo()
{
this->Chang_Game(new Chomoshot());
}
void Gametype::Chang_Game(GameStateP* State)
{
delete gameState;
gameState = State;
}
----------------------------------------------------------------------
これでバナナ、チョモランマを好きなタイミングで変えることができます。
今回 Chang_Gameは private にして外からは触れないようにしています。
GemeState* 型にすることによりそれぞれに合わせてbanana->やChomoranma->と書かなくてよくなり
インスタンス化だけでそれぞれの関数を呼ぶことができます。
最後にメイン部分。
----------------------------------------------------------------------
void main::Comment(const Gametype* game)
{
DrawString(100, 50, "キャラクター", GetColor(255, 255, 255));
DrawString(100, 100, game->Get_Char(), GetColor(255, 255, 255));
DrawString(100, 150, "ゲームの種類", GetColor(255, 255, 255));
DrawString(100, 200, game->Get_type(), GetColor(255, 255, 255));
}
void main::Update()
{
if (IsButtonPressed(PAD_INPUT_UP))
{
mGtype->banana();
}
else if (IsButtonPressed(PAD_INPUT_DOWN))
{
mGtype->chomo();
}
}
void main::Draw()
{
Comment(mGtype);
DrawString(0, 0, "main", GetColor(100, 255, 100));
}
----------------------------------------------------------------------
このようにメインに書くことがとても少なくなります。
たとえミニゲームの数が100に増えてもクラスと Gametypeの切り替え部分が多くなるだけでメインはほぼ変わりありません。
今回で私が知ったことはこの程度で正解かどうかは差で下ではないですが
もっと勉強して使いこなせるようになれたらと思います。