★プレイヤーキャラクター 移動★


これまでは動きの無いテーブルゲームやパズルゲームを作ってきました。

今回からは動きのあるゲームの基礎を説明したいと思います。

ただ、規模の大きなゲームは説明しきれませんので、部分的に作っていきます。


画像の準備


これまでは元画像として「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クラスの作成と描画


オブジェクトとしてプロジェクトフォルダに「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);
}

実行して、カーソルキーを押してみてください。

<実行結果 クライアント領域のみ>


次回は「スピード調整」について説明します。


次へ

戻る

目次へ