表紙の写真

ゲームループ(2)

ゲームの進行はとても単純です。キャラクタを動かし、そしてキャラクタを描画します。1体動かして1体描画するのではなく、すべてのキャラクタを動かして、すべてのキャラクタを描画します。

たとえば、ダミーの関数を呼び出すとすれば、次のように書くことができます。

While(System::Update())
{
    MoveAllCharacters();
    DrawAllCharacters();
}

OpenSiv3Dだからこれだけ簡素に処理を書けますが、DirectXを使って処理を書こうとすると、Windowのメインループを書いてWindowsのメッセージを処理させ、次にDirectXのメッセージを処理させ、その上でゲーム処理を書かなければなりません。かなり面倒です。


Taskシステムを使った実装

Taskシステムを使うと「タスクコールグループ」という概念を利用できるので、ゲームループを次のように書くことができます。

While(System::Update())
{
    TaskCall::All::Update(TaskGroups::Moving);
    TaskCall::All::Update(TaskGroups::Drawing);
}

次のソースコードは、キーボードを使って自機を動かすためのサンプルです。タスクコールグループを分けて、移動処理をさせてから、描画処理をさせています。

タスクグループを分けるには汎整数値でグルーピングIDを振ればよいので、公式サイトに合わせて列挙体を使います。そろそろリファクタリングしてソースコードを分割したくなってきますね。

#include <Siv3D.hpp>
#include <rnfs.h>

typedef TextureRegion SoftwareSpriteT;

enum TaskGroups {
    Moving,
    Drawing
};

class Player : public Task {
private:
    Vec2 m_Pos;
    TaskCall m_Move;
    TaskCall m_Draw;
    Array<SoftwareSpriteT>& m_Sprite;
    int m_Framecounter;
public:
    Player(Array<SoftwareSpriteT>& player) : Task(TaskDestroyMode::None)
        , m_Pos(Vec2(0, 0))
        , m_Move(this, &Player::Move, TaskGroups::Moving)
        , m_Draw(this, &Player::Draw, TaskGroups::Drawing)
        , m_Sprite(player)
        , m_Framecounter(0)
    {}
private:
    void Move()
    {
        if (KeyUp.pressed()) {
            m_Pos.y--;
        }
        else if (KeyDown.pressed()) {
            m_Pos.y++;
        }

        if (KeyLeft.pressed()) {
            m_Pos.x--;
        }
        else if (KeyRight.pressed()) {
            m_Pos.x++;
        }
    }

    void Draw()
    {
        m_Sprite.at(0).draw(m_Pos);
    }
};

void Main()
{
    if (static_cast<int>(Graphics::GetDisplayRefreshRateHz()) != 60)
    {
        Graphics::SetTargetFrameRateHz(60);
    }

    Texture texPlayer(U"player.png");
    Array<SoftwareSpriteT> player;
    for (int x : {0}) {
        player.push_back(texPlayer(64, 80, 32, 16));
    }

    Create<Player>(player);

    while (System::Update())
    {
        TaskCall::All::Update(TaskGroups::Moving);
        TaskCall::All::Update(TaskGroups::Drawing);
    }
    Task::All::Clear();
}

やっと自機を登場させることができました。DirectXで作成したときも、じっくりプログラムをする時間が取れなかったので、このようにひとつずつフレームワークの動作を確認しながら実行させていました。




この記事が気に入ったらサポートをしてみませんか?