Posted at
Siv3DDay 9

描画オブジェクトを管理するDrawableListを作った

More than 1 year has passed since last update.

Siv3D Advent Calendar 2016 9日目の記事です.


はじめに

これまでに何度かSiv3Dを使ってゲーム製作を行ってきましたが,製作を進めていくと毎回ある1つの問題に直面していました.

その問題とは「画面に描画するオブジェクトの管理が大変」ということです.

ゲームが複雑なものになればなるほど,シーン中に描画するオブジェクトが増えてきます.Siv3Dは描画周りが簡潔に書けるライブラリでとても助かっているのですが,それでもオブジェクトの量が増えてくると管理が大変になってきます.

そこで,描画するオブジェクトを一括管理できるDrawableListというものを作って,実際に導入してSiv3Dでゲームを作ってみました.


DrawableListについて

DrawableListを使うことで,次のようなことが実現できます.


  1. 描画順番をレイヤー風に指定可能

  2. 描画の要否をオブジェクトごとに設定可能

  3. シーンのdraw関数がスッキリする!

描画順番は,お絵かきソフトでよく見るレイヤーのようなイメージで設定することができます.レイヤー番号を指定することで,そのレイヤーにオブジェクトが描画されます.


実装と使い方

まずは描画するオブジェクトに実装させるDrawableクラスです.


Drawable.h

#pragma once


class Drawable
{
private:
bool m_isVisible;

public:
Drawable() : m_isVisible(true) {};
virtual ~Drawable() = default;

public:
virtual void draw() const = 0;

void show()
{
m_isVisible = true;
}

void hide()
{
m_isVisible = false;
}

bool isVisible() const
{
return m_isVisible;
}
};


基本的に,描画するオブジェクトはこのクラスを継承して作成し,draw関数をオーバーライドします.こうして作られたDrawableなオブジェクトをDrawableListを使って管理します.


DrawableList.h

#pragma once

#include <map>
#include <memory>
#include <algorithm>
#include "Drawable.h"

class DrawableList
{
private:
std::multimap<int, std::shared_ptr<Drawable>> m_drawables;

public:
DrawableList() = default;
~DrawableList() = default;

public:
void add(std::shared_ptr<Drawable> drawable, int layer)
{
m_drawables.insert(std::make_pair(layer, drawable));
}

void drawAll() const
{
std::for_each(m_drawables.begin(), m_drawables.end(), [](auto p) {
if(p.second->isVisible()) {
p.second->draw();
}
});
}
};


DrawableList::add関数にDrawableを実装したオブジェクトのstd::shared_ptrとレイヤー番号を渡すことで,DrawableListに登録されます.あとは,描画したいときにDrawableList::drawAll関数を呼べば,レイヤー番号の順番に描画されます.また,multimapを使用しているので,複数のオブジェクトで同じレイヤー番号を指定することが可能です.

ここで載せているソースコードですが,コメントと動作例を追加したものをGistでも公開しています.

DrawableListの実装例 - Gist


導入してみた

このDrawableListを,実際に以下のプロジェクトで導入してみました.GitHubでソースコードを全て公開しているので,気になる方は読んでみるといいかもしれません.

なんとなクエスト - IndistinQuest/Game - GitHub

実際に導入してみると,オブジェクトの管理がぐっと楽になりました.特にレイヤー機能がとても便利で,プロジェクトメンバーからの評判も上々でした.このDrawableListを拡張したGameObjectManager的なものがSiv3Dに導入されて,SceneManagerのような形で管理できればゲームがもっと作りやすくなるんじゃないかなぁとか思いました.


まとめ


  • 描画するオブジェクトの管理はDrawableListのようなものを使うと便利

  • Siv3DにGameObjectManagerみたいな機能があったら便利かもしれない


明日は @voidProc さんの記事です.

よろしくお願いします.