次は発射した弾を動かしましょう。
前回の最初に書いたように「右」に移動させる事にします。
キャラクターを右に移動させるには「転送先X座標」を増やせば良かったですね。
同じように、弾の「転送先X座標」を増やす事で右に移動させる事が出来ます。
まずは「Shot.h」を開き、publicメンバ関数として「Update関数」を、privateメンバ関数として「Move関数」の宣言を追加します。
class Shot { public: Shot(); //初期化 void Initialize(); //発射 void Shoot(const int x, const int y); //更新 void Update(); //描画 void Draw(Engine *pEngine); private: const int WIDTH; const int HEIGHT; const int SPEED; bool m_bShooting; int m_x; int m_y; RECT m_sour; RECT m_dest; //移動 void Move(); }; |
「Shot.cpp」を開き「Shoot関数」の下に「Update関数」の本体を追加します。
void Shot::Update() { Move(); } |
さらに「Draw関数」の下に「Move関数」の本体を追加します。
void Shot::Move() { if (m_bShooting) { m_x += SPEED; } } |
ここでも「発射中フラグ」がONの場合だけ座標を変更します。
「SceneGame.cpp」を開き、「Update関数」から「Shotクラス」の「Update関数」を呼び出します。
void SceneGame::Update()
{
m_player.Update(m_pEngine, m_shot);
m_shot.Update();
}
|
それでは実行してみましょう。
発射した弾が右へ移動していけばOKです。
弾は無事に移動しましたが、1発撃ったらお終いで2発目の弾は撃てません。
「発射中フラグ」がOFFの時にしか弾は撃てませんから、どこかで「発射中フラグ」をOFFにしないといけません。
2Dゲームでは「画面外」の世界はほぼ「無い事」になっています。
発射した弾が画面外でもずっと進んでいる事はありませんし、画面外の敵に弾が命中する事もありません。
つまり「画面外に出た時点で弾は消えている」と考えて良いと思います。
そこで「Shot.cpp」を開き、「Move関数」を次のように変更しましょう。
void Shot::Move()
{
if (m_bShooting) {
m_x += SPEED;
if (m_x >= WindowSetting::WINDOW_WIDTH) {
m_bShooting = false;
}
}
}
|
「転送先X座標」が画面端(WINDOW_WIDTH)を越えたら「発射中フラグ」をOFFにします。
実行して確かめてみましょう。
弾が画面外に出たら、次の弾が発射出来るようになりました。
とりあえず弾の基本は出来た訳ですが、少し調整をしたいと思います。
弾の発射位置をよく見ると、プレイヤーキャラクターの左上から発射されています。
これは「Player.cpp」の「Shoot関数」に原因があります。
void Player::Shoot(Engine *pEngine, Shot &refShot) { if (pEngine->GetKeyState(DIK_Z)) { refShot.Shoot(m_x, m_y); } } |
「Shotクラス」の「Shoot関数」に渡している引数を見てください。
「m_x」「m_y」はプレイヤーキャラクターの「転送先座標」です。
当然、プレイヤーキャラクターの「左上」の座標ですから、弾の初期座標もキャラクターの「左上」になってしまっているのです。
例えば、プレイヤーキャラクターの「中心」から弾を発射したいと考えた場合、キャラクターのサイズと弾のサイズを元に次のようにします。
プレイヤーキャラクターの幅 32ピクセル 弾の幅 16ピクセル (32 − 16) ÷ 2 = 8
プレイヤーキャラクターのX座標から8ピクセル移動させる事で横方向の中心の位置が求まります。
同じように縦方向も計算する事が出来ます。
これを実現させるには、弾の幅と高さを「Playerクラス」で使えるようにならないといけません。
「Shot.h」を開き、getter関数を追加しましょう。
class Shot { public: Shot(); //初期化 void Initialize(); //発射 void Shoot(const int x, const int y); //更新 void Update(); //描画 void Draw(Engine *pEngine); //幅の取得 int GetWidth() const; //高さの取得 int GetHeight() const; private: const int WIDTH; const int HEIGHT; const int SPEED; bool m_bShooting; int m_x; int m_y; RECT m_sour; RECT m_dest; //移動 void Move(); }; |
「Shot.cpp」を開き、「Draw関数」の下にgetter関数の本体を追加します。
//幅の取得 int Shot::GetWidth() const { return WIDTH; } //高さの取得 int Shot::GetHeight() const { return HEIGHT; } |
次に「Player.cpp」を開き、「Shoot関数」を変更します。
void Player::Shoot(Engine *pEngine, Shot &refShot) { if (pEngine->GetKeyState(DIK_Z)) { int adjustX = (WIDTH - refShot.GetWidth()) / 2; int adjustY = (HEIGHT - refShot.GetHeight()) / 2; refShot.Shoot(m_x + adjustX, m_y + adjustY); } } |
上の計算式を使って、プレイヤーキャラクターの「中心」を弾の初期座標にしました。
それでは実行してみましょう。
よく見ないと分からないかも知れませんが、プレイヤーキャラクターの「中心」から弾が発射されるようになりました。
最後に描画順について考えてみましょう。
今は「プレイヤーキャラクター」「弾」の順番で画像を表示しています。
「SceneGame.cpp」の「Draw関数」を見れば分かりますね。
void SceneGame::Draw() { m_back.Draw(m_pEngine); m_player.Draw(m_pEngine); m_shot.Draw(m_pEngine); } |
この順番なので、プレイヤーキャラクターの上に弾の画像が表示されるのです。
もし、プレイヤーキャラクターの裏に弾の画像を表示したい場合、描画順を変える必要があります。
void SceneGame::Draw()
{
m_back.Draw(m_pEngine);
m_shot.Draw(m_pEngine);
m_player.Draw(m_pEngine);
}
|
実行してみます。
微妙ですが、プレイヤーキャラクターの後ろから弾が発射されています。
ゲームを作る際に大事な事の1つは、「遊ぶ人がどう感じるか」と言う微妙な感覚です。
微妙ですが、何か違和感があるとスムーズに遊べなくなります。
特に自分で作ったゲームに対しては、自分では違和感を持てないものです。
他の人にテストプレイをしてもらう事、問題点を指摘してもらう事は非常に大事な事ですから、どんどん他人にプレイしてもらうようにしてみてください。