これまでは動きの無いテーブルゲームやパズルゲームを作ってきました。
今回からは動きのあるゲームの基礎を説明したいと思います。
ただ、規模の大きなゲームは説明しきれませんので、部分的に作っていきます。
これまでは元画像として「2のn乗×2のn乗の正方形」の画像を使うよう説明してきました。
2016/12/21にシステムをアップデートした際に、グラフィックボードが対応していれば、画像サイズはフリーになりました。
対応していなければ、実行時にエラーが表示されますので、「2の累乗×2の累乗」に直してください。
正方形で無くとも大丈夫だと思います。
と言う訳で、今回使用する画像は↓です。
画像サイズは「64×128ピクセル」で、キャラクター1体のサイズは「32×32ピクセル」です。
※昔、知り合いに書いてもらった画像ですので、フリー素材サイトにはありません。
※似たような画像はフリー素材サイトにもありますので、別の画像を使いたい方は探してみてください。
画像をダウンロードして「Character.png」と言う名前で「Resource\\Textureフォルダ」に格納してください。
「GameBase.h」を開き、パス付ファイル名を定数化しましょう。
//-----------------------------------------------------------------------------
//ゲーム中で使用するテクスチャ、BGM、SE、フォントのパス付ファイル名を書きます。
//-----------------------------------------------------------------------------
namespace KeyString
{
const std::string TEXTURE_CHARACTER = "Resource\\Texture\\Character.png";
}
|
「SceneGame.cpp」を開き、「Start関数」で画像を追加します。
//=============================================================================
// シーンの実行時に1度だけ呼び出される開始処理関数
//=============================================================================
void SceneGame::Start()
{
m_pEngine->AddTexture(TEXTURE_CHARACTER);
}
|
オブジェクトとしてプロジェクトフォルダに「Player.h」と「Player.cpp」を追加しましょう。
「Player.h」を開き、最初に必要なデータとともにPlayerクラスを宣言します。
class Player {
public:
Player();
//描画
void Draw(Engine *pEngine);
private:
const int WIDTH;
const int HEIGHT;
RECT m_sour;
RECT m_dest;
};
|
描画に必要な定数やRECT構造体、関数を用意しました。
動きを確認するためには描画されていなければなりませんので、最初は描画関数から作ります。
「Player.cpp」を開き、コンストラクタ関数と「Draw関数」を作りましょう。
転送用座標については、元画像の左上のキャラクターを画面の左上(原点)に転送するように設定します。
Player::Player() : WIDTH(32) , HEIGHT(32) { } void Player::Draw(Engine *pEngine) { SetRect(&m_sour, 0, 0, WIDTH, HEIGHT); SetRect(&m_dest, 0, 0, WIDTH, HEIGHT); pEngine->Blt(&m_dest, TEXTURE_CHARACTER, &m_sour); } |
Playerクラスをシーンに組み込んで、描画できるようにします。
「GameBase.h」を開き、ヘッダファイルをインクルードしましょう。
//-----------------------------------------------------------------------------
// オブジェクトのヘッダファイルをインクルードします。
//-----------------------------------------------------------------------------
#include "Object\\Player\\Player.h"
|
「SceneGame.h」を開いて、Playerクラスの実体を作ります。
private: Player m_player; }; |
「SceneGame.cpp」の「Draw関数」で、Playerクラスの「Draw関数」を呼び出します。
//=============================================================================
// シーンの実行時に繰り返し呼び出される描画処理関数
//=============================================================================
void SceneGame::Draw()
{
m_player.Draw(m_pEngine);
}
|
実行してみましょう。
<実行結果 クライアント領域のみ>
後ろ向きのキャラクターが、画面の左上に表示されたらOKです。
さて、キャラクターを動かすとは「キャラクターの転送先座標を変更する」事です。
キー入力などによってキャラクターの転送先座標を変える事が出来れば動かせます。
そこで、Playerクラスに座標を追加してみましょう。
初期値は「Initialize関数」を作って設定します。
class Player { public: Player(); //初期化 void Initialize(); //描画 void Draw(Engine *pEngine); private: const int WIDTH; const int HEIGHT; int m_x; int m_y; RECT m_sour; RECT m_dest; }; |
「Player.cpp」のコンストラクタ関数の下に「Initialize関数」の本体を追加します。
void Player::Initialize() { m_x = 0; m_y = 0; } |
コンストラクタ関数で初期値を設定しないのは、「Initialize関数」を呼び出せば値がリセット出来るからです。
コンストラクタは実体が作られた時しか実行されません。
Playerクラスの「Draw関数」の転送先の式を座標を使った式に変更します。
void Player::Draw(Engine *pEngine) { SetRect(&m_sour, 0, 0, WIDTH, HEIGHT); SetRect(&m_dest, m_x, m_y, m_x + WIDTH, m_y + HEIGHT); pEngine->Blt(&m_dest, TEXTURE_CHARACTER, &m_sour); } |
このような考え方は「転送先座標の計算」でもやりました。
「SceneGame.cpp」の「Start関数」で、Playerクラスの「Initialize関数」を呼び出しましょう。
//============================================================================= // シーンの実行時に1度だけ呼び出される開始処理関数 //============================================================================= void SceneGame::Start() { m_pEngine->AddTexture(TEXTURE_CHARACTER); m_player.Initialize(); } |
実行してみてください。
<実行結果 クライアント領域のみ>
プログラムの形は変わっても、転送先座標自体は変わっていませんので、同じ場所に表示されます。
転送先座標が変数になりましたので、この変数をキー入力で変更する事が出来れば良い訳です。
キャラクターを動かすための関数を追加しますが、少し工夫します。
「Player.h」を開き、クラスに追加しましょう。
class Player { public: Player(); //初期化 void Initialize(); //更新 void Update(Engine *pEngine); //描画 void Draw(Engine *pEngine); private: const int WIDTH; const int HEIGHT; int m_x; int m_y; RECT m_sour; RECT m_dest; //移動 void Move(Engine *pEngine); }; |
publicメンバ関数として「Update関数」を追加し、privateメンバ関数として「Move関数」を追加しました。
プレイヤーの動作と言うのは移動するだけではありません。
様々な動作を定義するのに「Update(更新)」と言う名前でまとめておきます。
「Update関数」の中から「Move関数」などの細かい動作用関数を呼び出すように作りましょう。
どちらもエンジンクラスのポインタを引数としていますが、キー入力のためにはエンジンクラスが必要です。
それでは「Player.cpp」を開き、「Initialize関数」の下に「Update関数」を追加しましょう。
void Player::Update(Engine *pEngine) { Move(pEngine); } |
今のところは「Move関数」を呼び出すだけです。
続いて「Draw関数」の下に「Move関数」を追加します。
キャラクターを動かすためのキーは、カーソルキー(↑→↓←)を使いましょう。
void Player::Move(Engine *pEngine) { if (pEngine->GetKeyState(DIK_UP)) { } if (pEngine->GetKeyState(DIK_RIGHT)) { } if (pEngine->GetKeyState(DIK_DOWN)) { } if (pEngine->GetKeyState(DIK_LEFT)) { } } |
まだ中身はありませんが、「GetKeyState関数」を使っている事に注目してください。
これまではマウスをクリックするなど、1度だけボタンを押すのを調べていましたが、キャラクターを動かす時などはキーは押しっぱなしになるはずです。
「押しっぱなし」をチェック出来るのが「GetKeyState関数」です。
チェックの順番は「上右下左」となっていますが、元画像の向きに合わせて順番を決めました。
さて、ここからが本題です。
今、キャラクターの転送先座標は
m_x = 0; m_y = 0; |
となっています。
この「m_x」を1に変更すると、少し右に転送位置が変わります。
2に変更するともう少し右に、3に変更するとさらに右・・・
逆に「m_x」を減らすと転送位置は左にずれていきます。
「m_y」については、減らすと上に、増やすと下にずれていくはずです。
そこで、次のようにコードを追加します。
void Player::Move(Engine *pEngine) { if (pEngine->GetKeyState(DIK_UP)) { m_y--; } if (pEngine->GetKeyState(DIK_RIGHT)) { m_x++; } if (pEngine->GetKeyState(DIK_DOWN)) { m_y++; } if (pEngine->GetKeyState(DIK_LEFT)) { m_x--; } } |
押したキーに合わせて座標を増減させます。
「SceneGame.cpp」の「Update関数」で、Playerクラスの「Update関数」を呼び出しましょう。
//=============================================================================
// シーンの実行時に繰り返し呼び出される更新処理関数
//=============================================================================
void SceneGame::Update()
{
m_player.Update(m_pEngine);
}
|
実行して、カーソルキーを押してみてください。
<実行結果 クライアント領域のみ>
次回は「スピード調整」について説明します。