スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ローグライクゲームを作ってみよう!  その7 ~生成システム~

まず、現状報告
--------------------------------------------
・アプリ開発
・3Dゲーム開発
・2D(日本語パズルのやつ)ゲーム開発
・ローグライクゲーム(解説用)開発

--------------------------------------------
上記を同時進行してます。
やる事が沢山あると、作業がなかなか進まないものですね。


とりあえず、ローグライクの解説を始めます。
今回やるのは生成システムです。

DXライブラリだと、画像を読み込ませたらint型のハンドルを取得すると思うのですが、
これ、関数ごとにバラバラに取得してたら管理がゴチャゴチャになります。

(DXライブラリの場合は、DxLib_End()関数で自動で解放処理をやってくれるので良いのですが、
全部DirectXとかで実装しようとすると、間違いなく開放忘れが出てくるだろう。)

なので、今回は
------------------------------------
・オブジェクトの生成
・生成したオブジェクトの管理

------------------------------------
に焦点を絞って解説していきたいと思います。


まず生成について。
-------------------------------------------------------------
【1】IFactoryクラスを定義。 (Factoryクラスのインターフェース)
【2】IFactoryクラスを継承した、Factoryクラスを定義

-------------------------------------------------------------

やるのは上記だけです。簡単ですね。

【1】IFactoryクラスを定義

#pragma once
#include< vector >

enum FactoryID {
FACTORY_TEXTURE,
FACTORY_DRAWER
};

class IFactory {
public:
IFactory();
virtual ~IFactory();
static int Create( FactoryID t_ID, std::vector< int >& t_ParamVec );
virtual int CreateObject( std::vector< int >& t_ParamVec ) = 0;
void ChangeIntToStr( std::vector< char >& t_CharVec, std::vector< int >& t_ParamVec, int t_OffSet, int t_StringNum );
private:

};

int IFactory::Create( FactoryID t_ID, std::vector< int >& t_ParamVec )
{
int result = -1;
CTextureFactory t_TextureFactory;
CDrawerFactory t_DrawerFactory;

switch( t_ID ){
case FACTORY_TEXTURE: result = t_TextureFactory.CreateObject( t_ParamVec );
break;
case FACTORY_DRAWER: result = t_DrawerFactory.CreateObject( t_ParamVec );
break;
default:break;
}

return( result );
}

ここでポイントは2つ。

■一つ目。
IFactoryの方では、CreateObject関数を純粋仮想関数にしています。

つまり、IFactoryクラスを継承してCTextureFactoryクラスを作った場合、
必ずCreateObject関数を定義して、この関数でテクスチャを生成
してね、
と言っている訳です。

■二つ目。
IFactoryクラスには、staticなCreate関数があります。
これは、"何か"のオブジェクトを作成したいときに使います。

"何か"というのが重要です。

つまり、IFactory.hさえインクルードすれば、
テクスチャだろうが描画オブジェクトだろうが生成できる

という事です。

#include"IFactory.h"

int WINAPI WinMain(//省略){
IFactory::Create( FACTORY_TEXTURE, t_ParamVec ); //テクスチャ作成
IFactory::Create( FACTORY_DRAWER, t_ParamVec2 ); //描画オブジェクト作成
}


もし、IFactoryというインターフェースが無ければ、
下記の様に各Factoryクラスのヘッダをインクルードしなければならず、
かなり面倒くさい事になります。

#include"CTextureFactory.h"
#include"CDrawerFactory.h"


int WINAPI WinMain(//省略){
CTextureFactory t_TextureFactory;
CDrawerFactory t_DrawerFactory;

t_TextureFactory.CreateTexture( t_ParamVec ); //テクスチャ作成
t_DrawerFactory.CreateDrawer( FACTORY_DRAWER, t_ParamVec2 ); //描画オブジェクト作成
}


更に、フォルダ構成を変えた場合は、
下記の様にファイルパスを全部書き換えなければならないですし、
【変更前】 #include"CDrawerFactory.h"
【変更後】 #include"../Factory/CDrawerFactory.h"


また、Factoryクラスの名前を変えたら、
その変更も反映させないと行けません。
【変更前】 #include"CDrawerFactory.h"
【変更後】 #include"CDrawerFactory2.h"


なので、絶対不変であるIFactoryインターフェースを定義しておき、

WinMainなどからは、Factoryクラスの内部仕様が変更されようが、
IFactory.hを読み込んでIFactory::Create関数を
呼び出せば、どんなオブジェクトであれ生成出来る
という風にしたのです。

※DxLib.hさえインクルードすれば、
 LoadDivGraph関数だろうがSetWindowSize関数だろうが使える、というのに近い。


次に、オブジェクトの管理。

オブジェクトの管理は、
・Factoryクラスが、対応するManagerにオブジェクトを登録
・Managerクラスはシングルトンパターンになっており、
 プログラムが終了するまで、オブジェクトを保持する。

・任意のタイミングで、オブジェクトを削除したい場合は、
 各Managerクラスの削除関数を呼ぶ。

という風になってます。

※Singletonパターン … 必ずオブジェクトが一つのみ生成される事を保証する。
             2つ以上は生成されない。


Singleton(シングルトン)についてですが、
自分は自作したテンプレートのSingletonクラスを使用しています。

細かい原理の説明はしませんが、
とりあえず、Singletonパターンにしたいクラスがある場合、
------------------------------------------------
【1】CSingleton.hをインクルード
【2】CSingleton<クラス名>を、publicで継承する
【3】CSingleton<クラス名>を、friendに指定する。

------------------------------------------------
とすればOKです。


例:CTestクラスをSingletonパターンにしたい場合。
#pragma once
#include"CSingleton.h"

class CText : public CSingleton< CTest > {
friend class CSingleton< CTest >;
public:
CTest();
~CTest();
int MyFunc();
};

ついでに、使用する場合。
CTest& t_Test = CTest::getInstance();
t_Test.MyFunc();

(getInstance関数で、インスタンスへの参照が返るので、それを受け取る。)


最後に。
今回のソースコードは下記になっています。
だんだん量が増えてきましたね。

■Base
■Factory
┃┣CDrawerFactory.h
┃┣CDrawerFactory.cpp
┃┣CTextureFactory.h
┃┣CTextureFactory.cpp
┃┣IFactory.h
┃┗IFactory.h
■Manager
┃┣CDrawerManager.h
┃┣CDrawerManager.cpp
┃┣CTextureManager.h
┃┗CTextureManager.cpp
■Resource
┃┣CDrawer2D.h
┃┣CDrawer2D.cpp
┃┣CDrawerBase.h
┃┗CDrawerBase.cpp
■Support
 ┗CSingleton.h

main.cpp


あ、そうだ。
画像読み込みの補足説明をしておきます。

画像を読み込む場合、ファイル名をint型に変更してパラメータとして渡し、
Factoryクラス内で、また文字列に変換して画像を読み込んでます。


■変換の図
grade.jpg → 103,114,97,100,101,46,106,112,103 → grade.jpg

何でこのようにするかというと、
下記の様に、全部int型のvectorを引数にしてオブジェクトを生成したいからです。
IFactory::Create( FACTORY_TEXTURE, t_Vec );

また、全部int型にしておくと、外部ファイル化して、Loaderクラスを作った時に便利になります。
これについては、次回 解説します。


■サンプルのソースコードについて。
Enter … 描画順変更
「→」キー … 特定の描画オブジェクトを非表示に変更
「←」キー … 特定の描画オブジェクトを表示に変更


上記の動作を行う様にしています。
また、画像を回転、拡大縮小、半透明表示などに対応させています。

※不具合があったら適宜修正します。

【ソースコード】 http://rudora3.web.fc2.com/RogueSample2.zip
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント

No title

同時進行が多い場合は割りきっていくつか捨てています

Re: No title

やっぱり、優先順位を決めるか、
都合が合わなければいくつかは中断・後回しにしないといけないですよねv-292

プログラミングは特に、細切れの時間よりも
まとまった時間が1回取れる方が開発が進みやすい
ような気がするので、
時間配分や、作業に割り当てる時間を考えてみようと思いますv-293
(アプリ開発の方を一旦中断して、PCゲームの方に注力してみる予定です)
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。