lumino trail

ゲームエンジン作ってます。Github:https://github.com/lriki/Lumino Twitter:https://twitter.com/lriki8

開発状況 2020 #3

0.9.0 リリースしました

Lumino | Lumino website

Ruby 対応がメインです。

https://luminoengine.github.io/articles/documents/first-tutorial/img/object-1.png

↓こんな感じの雰囲気です。

require "lumino"

class App < Application
  def on_init
    Engine.render_view.guide_grid_enabled = true
    Engine.camera.set_position(5, 5, -5)
    Engine.camera.look_at(0, 0, 0)

    box1 = BoxMesh.new
    box1.set_position(1, 0, 0)

    box2 = BoxMesh.new
    box2.set_position(0, 2, 0)

    box3 = BoxMesh.new
    box3.set_position(0, 0, 3)
  end
end

App.new.run

また、チュートリアルを全体的に直してます。

まだまだ未実装の部分は多いですが、何となくゲームエンジンとして目指したい全体像が見えてきたかなというところです。

画面遷移実装中

エディタはあまり使わずプログラムがしがし書くときに、タイトル画面やゲームプレイ画面を効率よく開発するための仕組みです。

仕組み自体は Lumino 開発の初期からあったのですが、画面単位の名前を Scene にするか Level にするか、長い闘いの末、

  • Level: 画面単位
  • Scene: シーン描画全体にかかわるユーティリティ

としてみました。

Level はこんな感じ↓で実装します。よくあるやつですが。

// タイトル画面
class TitleLevel : public Level
{
    void onStart() override
    {
        // 初期化

        // 背景を灰色にする
        Scene::setBackgroundColor(Color::Gray);

        // 画面遷移時のマスク画像を設定する
        Scene::setTransitionEffectMaskTexture(Texture2D::load(u"Transition1.png"));
    }

    void onUpdate() override
    {
        // 更新
        
    if (Input::triggered(u"submit")) {
           // キーが押されたら別の画面へ移動
           Scene::gotoLevel(u"Game");
        }
    }
};

また画面遷移のエフェクトも標準搭載してます。

単純なフェードイン・フェードアウトのほか、以前のツクールシリーズにあった、マスク画像を用いたクロスフェードも使えます。

これは一般的な雲画像を使った遷移エフェクトです。

f:id:lriki:20200331202228g:plain

一応、画面単位ということで Level を説明してますが、実装は UE4 の Level や Unity の Scene と同じです。

Level 自体アセットファイルに保存してエディタでいじったり、普通にマップ作るのにも使います。 あとマルチレベルのロードや先行ロード、非同期ロード、Loading 画面とかいろいろ応用できます。の予定。

画面遷移くらいなら次のリリースに入れられるかな。

3D オートタイルを作成中

作成中のゲームでビジュアルを、全部 2D にするのか、背景 3D でキャラ 2D にするのか、いろいろ考え中です。 この 3D オートタイルは、そんな中で出来上がってきたコンポーネントです。

イメージ的には RPG ツクールシリーズの床・壁オートタイルがそのまま Voxel になる感じです。

Lumino の標準機能にするかは未定ですが、できれば入れたいです。 プロシージャルマップとか、コードファーストのテライン構築との相性は抜群だと思う。 あと3Dモデル用意しなくても、好きなタイルマップ素材もってくればすぐ3Dマップが作れたりします。

f:id:lriki:20200331203931p:plain

Instancing 対応中

何も考えずに 3D オートタイル実装してみたら描画がとんでもなく重くなったので、Instancing に挑戦しました。

↓のような感じで使います。

void onStart() {
    batch = InstancedMeshList::create(mesh, material);
}

void onRender(RenderingContext* context) {
    batch->reset();
    for (たくさん) {
        batch->drawMesh(transform);
    }
    context->draw(batch);
}

泥臭く自分で描画コード組む用の API なので、Unity みたいな、マテリアルで Instancing 指定するような使い方はまた別になります。

ちなみにオートタイルは、1タイルが↓のように4つのサブタイルから成っていると考えて、

f:id:lriki:20200331204555p:plain

これが4隅5パターンあります。

f:id:lriki:20200331204956p:plain

組み合わせは全部で 48 パターンです。

f:id:lriki:20200331205020p:plain

で、3D の Voxel で考えるので、ひとつの Voxel あたり 6 面描きます。

前セクションの3Dマップの例だとマップの大きさは 30×30 なので、全平面マップでも最低 900 ドローコール必要になったりします。

単純な Voxel なら各面を四角形スプライトと考えて Dynamic な頂点バッファに四角形を詰め込みまくって描けばいいのではってなるのですが、 やってみたいのは風来のシレン2・3 であったり世界樹と不思議のダンジョンであったりするので、やっぱりメッシュで書きたかったです。

まぁ結果的に描画速度が当社比100倍くらいになったのでヨシ。

Asset シリアライザを変更中

Lumino は Archive クラスがオブジェクトの保存・復元を担当していますが、これは cereal とかをすごく参考にして実装したもので、 ものすごく C++ オブジェクトのシリアライズに特化しています。

何がマズイのかというと、Ruby オブジェクトをシリアライズするのに使えないです。いや実は 0.9.0 時点でも使えてはいるのですが、めちゃくちゃ使いづらい。 なので、API はかなり原始的になるけど Ruby とか他の言語で定義されたオブジェクトも Asset に保存できるように見直してます。

あと、これまでは JSON で保存してましたが YAML にします。 多分十分な機能のアセットエディタなんて直近じゃ作れるはずもないので、ある程度は手打ちもやむなしかなぁ…とか思ってます。 そのため (JSON と比べて) 人間が読み書きしやすいフォーマットとして YAML を使うことにしました。

UIダークテーマ追加

とは言うものの、多少使いづらくてもマップエディタは無いと結構ツラいです。特に 3D だと。

エディタもどきは既にあるのですが、今Luminoがサポートしてる唯一のテーマは Material-UI を参考に作っているものです。 どちらかというとマウスよりも指でタップ操作する向けのものなので、ボタンとかでかいです。エディタには使いづらい。

なのでデスクトップで作業するエディタ向けのテーマを作ってます。ついでに目が疲れにくくなるらしいダークにしてます。

f:id:lriki:20200331211232p:plain