続いてカードクラスを追加しましょう。
前回の背景クラスオブジェクトの追加方法を確認しながら「Card.h」と「Card.cpp」をプロジェクトに追加してください。
最終的にソリューションエクスプローラーが↓のようになっていればOKです。
「Card.h」を開き、Cardクラスを追加します。
//**************************************************************************** // // カードクラス // //***************************************************************************** #pragma once #include "..\\..\\GameBase.h" //----------------------------------------------------------------------------- // クラスの宣言を書きます。 //----------------------------------------------------------------------------- class Card { public: static const int SUIT; static const int NUMBER; static const int SMALL_CARD_WIDTH; //小さいカードの幅 static const int SMALL_CARD_HEIGHT; //小さいカードの高さ Card(); void Set(const int number, const int suit); void Draw(Engine *pEngine, const int destX, const int destY); private: static const int SMALL_CARD_X; //小さいカードの左座標 static const int SMALL_CARD_Y; //小さいカードの上座標 int m_number; int m_suit; RECT m_sour; RECT m_dest; }; |
一気に色々追加しましたが、少しずつ説明します。
このカードクラスは、カード1枚分のクラスです。
定数に「static」が付いているのは、神経衰弱でカードを52枚使うためです。
「static」が付いていれば定数の領域は1つしか用意されず、定数が使う領域を減らすことが出来ます。
「SUIT」「NUMBER」「SMALL_CARD_WIDTH」「SMALL_CARD_HEIGHT」は他のクラスでも使用するため、publicに配置しました。
「Set関数」はメンバ変数の「m_number」「m_suit」を初期化するための関数です。
「Draw関数」には転送先のX,Y座標を引数として渡すようになっています。
続いて「Card.cpp」を開き、実体を作りましょう。
//**************************************************************************** // // カードクラス // //***************************************************************************** #define _USING_V110_SDK71_ 1 #include "Card.h" using namespace KeyString; using namespace InputKey; //----------------------------------------------------------------------------- // クラスメンバの本体を書きます。 //----------------------------------------------------------------------------- const int Card::SUIT = 4; const int Card::NUMBER = 13; const int Card::SMALL_CARD_WIDTH = 40; const int Card::SMALL_CARD_HEIGHT = 60; const int Card::SMALL_CARD_X = 0; const int Card::SMALL_CARD_Y = 750; Card::Card() { } void Card::Set(const int number, const int suit) { m_number = number; m_suit = suit; } void Card::Draw(Engine *pEngine, const int destX, const int destY) { SetRect(&m_sour, SMALL_CARD_X + (m_number - 1) * SMALL_CARD_WIDTH, SMALL_CARD_Y + m_suit * SMALL_CARD_HEIGHT, SMALL_CARD_X + (m_number - 1) * SMALL_CARD_WIDTH + SMALL_CARD_WIDTH, SMALL_CARD_Y + m_suit * SMALL_CARD_HEIGHT + SMALL_CARD_HEIGHT); SetRect(&m_dest, destX, destY, destX + SMALL_CARD_WIDTH, destY + SMALL_CARD_HEIGHT); pEngine->Blt(&m_dest, TEXTURE_TRUMP, &m_sour); } |
これまでのプログラムを振り返れば、特に説明が必要なものはありません。
座標などは、元画像と比較しながら確認してみてください。
スライドパズルまでは、シーンの関数に直接ゲームのコードを書いてきました。
今回はゲーム部分もクラス化します。
再度プロジェクトフォルダを開き、「Memoryオブジェクト」を作成し「Memory.h」「Memory.cpp」をプロジェクトに追加してください。
※結果は書きませんので、分からなくなった場合は前回の内容を見返しながら作りましょう。
「Memory.h」を開きMemoryクラスを宣言します。
まずはカードを設定するところまで作りたいので、少しずつ追加していきます。
//**************************************************************************** // // 神経衰弱クラス // //***************************************************************************** #pragma once #include "..\\..\\GameBase.h" //----------------------------------------------------------------------------- // クラスの宣言を書きます。 //----------------------------------------------------------------------------- //前方参照 class Card; class Memory { public: Memory(); ~Memory(); void Initialize(); private: //カードクラス配列用ポインタ Card *m_pCard; }; |
Memoryクラスの前に「class Card;」とあるのは前方参照です。
リンク先の説明にもありますが、他クラスのポインタや参照を使うのであればインクルードではなく「前方参照」を使います。
今回は52枚のカードを「new」で確保した領域に格納するようにしました。
そのため「m_pCard」と言うポインタ変数を用意しています。
なぜ、元から配列にしないのかと言うと「Cardクラス」の「SUIT」「NUMBER」を使って、
Card m_card[Card::SUIT][Card::NUMBER]; |
や
Card m_card[Card::SUIT * Card::NUMBER]; |
と書いてもエラーになるからです。
理由はこちらに書いてあります。
ポインタ変数を用意し、「Initialize関数」で領域を確保してデストラクタ関数で領域を解放するように作ります。
「Memory.cpp」を開き、実体を作りましょう。
//**************************************************************************** // // 神経衰弱クラス // //***************************************************************************** #define _USING_V110_SDK71_ 1 #include "Memory.h" using namespace KeyString; using namespace InputKey; //----------------------------------------------------------------------------- // クラスメンバの本体を書きます。 //----------------------------------------------------------------------------- Memory::Memory() : m_pCard(NULL) { } Memory::~Memory() { if (m_pCard) { delete[] m_pCard; m_pCard = NULL; } } void Memory::Initialize() { m_pCard = new Card[Card::SUIT * Card::NUMBER]; for (int i = 0; i < Card::SUIT; i++) { for (int j = 0; j < Card::NUMBER; j++) { m_pCard[i * Card::NUMBER + j].Set(j + 1, i); } } } |
「Initialize関数」では、領域を確保し、カードの初期値を設定しています。
ここも、これまでのプログラムを振り返れば、特に説明しなくても大丈夫だと思います。
しかし、「Card::SUIT」「Card::NUMBER」のところでエラーが発生しています・・・
「GameBase.h」を開き次のヘッダをインクルードします。
//----------------------------------------------------------------------------- // オブジェクトのヘッダファイルをインクルードします。 //----------------------------------------------------------------------------- #include "Object\\Back\\Back.h" #include "Object\\Card\\Card.h" #include "Object\\Memory\\Memory.h" |
これで「Memory.cpp」のエラーは消えるはずです。
まだ描画部分は作っていませんが、ここまでのプログラムが動くようにします。
「SceneGame.h」を開き、神経衰弱クラスの実体を追加します。
private: //背景クラス Back m_back; //神経衰弱クラス Memory m_memory; }; |
「SceneGame.cpp」を開き「Start関数」でMemoryクラスの「Initialize関数」を呼び出します。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { m_pEngine->AddTexture(TEXTURE_TRUMP); m_memory.Initialize(); } |
とりあえず、実行しても何も起こりませんので、ビルドしてエラーが無い事を確かめてください。
カードの設定が出来ているかどうか確かめるためにも、カードの描画を先に作ります。
Memoryクラスにカードの配列がありますから、「Memory.h」を開いてプロトタイプを追加します。
//前方参照 class Card; class Memory { public: Memory(); ~Memory(); void Initialize(); void DrawCard(Engine *pEngine) const; private: //カードクラス配列用ポインタ Card *m_pCard; }; |
「DrawCard」という名前にしたのは、他にも描画すべきものがあるためです。
「Memory.cpp」を開き、関数の本体を作ります。
Memory::Memory()
: m_pCard(NULL)
{
}
Memory::~Memory()
{
if (m_pCard) {
delete[] m_pCard;
m_pCard = NULL;
}
}
void Memory::Initialize()
{
m_pCard = new Card[Card::SUIT * Card::NUMBER];
for (int i = 0; i < Card::SUIT; i++) {
for (int j = 0; j < Card::NUMBER; j++) {
m_pCard[i * Card::NUMBER + j].Set(j + 1, i);
}
}
}
void Memory::DrawCard(Engine *pEngine) const
{
for (int i = 0; i < Card::SUIT; i++) {
for (int j = 0; j < Card::NUMBER; j++) {
m_pCard[i * Card::NUMBER + j].Draw(pEngine, j * Card::SMALL_CARD_WIDTH, i * Card::SMALL_CARD_HEIGHT);
}
}
}
|
転送先座標は、タイル状に「縦4、横13枚」のカードを並べるため↑のように作りました。
※スライドパズルの時にも説明した方法を応用しています。
「SceneGame.cpp」を開き、「Draw関数」に追加します。
//============================================================================= // シーンの実行時に繰り返し呼び出される描画処理関数 //============================================================================= void SceneGame::Draw() { m_back.Draw(m_pEngine); m_memory.DrawCard(m_pEngine); } |
実行してみましょう。
<実行結果 クライアント領域のみ>
全てのカードが揃っていますが、表示場所に調整が必要ですね。
カードが画面の中央に配置されるよう、位置調整を行いましょう。
「Memory.h」を開き、調整のための定数を用意します。
//前方参照 class Card; class Memory { public: Memory(); ~Memory(); void Initialize(); void DrawCard(Engine *pEngine) const; private: const int ADJUST_X; //中央に転送するための調整用X座標 const int ADJUST_Y; //中央に転送するための調整用Y座標 //カードクラス配列用ポインタ Card *m_pCard; }; |
「Memory.cpp」のコンストラクタ関数で初期値を代入します。
※長くなってきたので必要な関数のみ書きだします。
Memory::Memory()
: ADJUST_X(60)
, ADJUST_Y(120)
, m_pCard(NULL)
{
}
|
※順番に気を付けてください。
最後に「DrawCard関数」を書き換えます。
void Memory::DrawCard(Engine *pEngine) const { for (int i = 0; i < Card::SUIT; i++) { for (int j = 0; j < Card::NUMBER; j++) { m_pCard[i * Card::NUMBER + j].Draw(pEngine, ADJUST_X + j * Card::SMALL_CARD_WIDTH, ADJUST_Y + i * Card::SMALL_CARD_HEIGHT); } } } |
実行してみます。
<実行結果 クライアント領域のみ>
続きは次回にしましょう。