本記事は、現在開発中のゲームエンジン(?)であるMansionEngineの試みについて皆さんに意見していただきたいがために作成しました。たくさんのコメントお待ちしております。
MansionEngineの試み
MansionEngine(https://github.com/Tokumochi/MansionEngine) の最大の試みは、ゲーム開発者が1フレーム間の処理の順序を明示的にしながら開発ができるようにするということです。
つまりどういうことか、例えば、2Dのシューティングゲームにおいて、体力がミリしか残っていないプレイヤーが敵の直前でWキーを押してしまった場合の処理を例に考えてみます。Wキーによるプレイヤーの前進、プレイヤーと敵の当たり判定、画面描画の処理順序の違いによって、ゲームオーバーの判定には以下のような違いが発生してしまいます。
このように処理順序によっては、開発者の想定にない動作が図らずに行われる可能性があります。MansionEngineでは、当たり判定や画面描画なども含めて処理順序を自由に変え明示的にしながら開発ができるようにすることで、開発者の想定にない動作が行われる可能性を減らし、さらに1フレーム間に行える処理の制約も広げられると考えています。
MansionEngineによる2Dシューティングゲームの開発
MansionEngineによってどのようにゲームが開発されるのか、簡単な2Dシューティングゲームの開発を例に説明します。
まずはプレイヤーがただWASDキーによって移動できるようにしたいです。そのために、以下のようなプレイヤーに関わるデータを用意します。
{
x: 0.0, // プレイヤーのX座標
y: 0.0, // プレイヤーのY座標
HP: 100, // プレイヤーの体力
}
このようなデータは、フレームを跨いだあとでも保持されなければいけません。MansionEngineには、このようなデータを"data"として保管し、1フレームの処理が終了した後でも保持し続けられる仕組みがあります。
また、MansionEngineでは、入力データの型・出力データの型・処理コードの3つによって構成され、関数的役割を持つ"process"を作成できます。プレイヤーを操作できるようにするために以下のようなprocessを作成します。
{ // 入力データの型
player: {
x: float,
y: float,
HP: int,
}
}
// コード
if(Input("W")) moved_player.y = player.y - 3;
if(Input("A")) moved_player.x = player.x - 3;
if(Input("S")) moved_player.y = player.y + 3;
if(Input("D")) moved_player.x = player.x + 3;
{ // 出力データの型
moved_player: {
x: float,
y: float,
HP: int,
}
}
さらに、MansionEngineではゲームを構成するうちの1機能を実装するための空間である"room"を作成することができます。これまでに作成したdata,processをroom上に配置して繋げ合わせることで、実際にゲームとして動作させることができます。先ほどの、プレイヤーのdata、プレイヤー操作のprocessの他に、プレイヤーのdataを新しくセットするprocessを用意し、以下のようにroom上に配置・接続させます。なお、緑色がdata、赤色がprocess、緑色の上に赤色が乗っているものはdataセット用のprocessを表しています。
上のroomを実行し、処理が毎フレーム行われることによってプレイヤーをWASDキーによって自由に操作できます。しかし、上のままでは画面に何も表示されないため、実際に正しくプレイヤーが動けているのか確認できません。そこで、デバッグモードによって確認しようと思います。デバッグモードでは、通常のroomに配置されているdataやprocessに加え、デバッグのためのdataやprocessを配置して接続することができます。デバッグモードにおいて、新たにプレイヤー描画のprocessを用意して、以下のようにroom上に配置・接続させます。なお、灰色の上に乗っているdata、processは、デバッグモードにおいて新たに追加されたものであることを表しています。
開発者はroomに対して通常実行とデバッグ実行の2つの実行方法を行うことができます。通常実行では、デバッグモードにおいて追加されたプレイヤー描画のprocessは実行されず、先ほどと同様の実行がされます。対して、デバッグ実行では、デバッグモードにおいて追加されたdata、processも実行されるため、画面に描画されたプレイヤーを確認することによって、正しくプレイヤーが動けているかどうかをテストすることが可能です。
ここまでで、プレイヤーを操作するというゲームの1機能を実装できたので、SPACEキーを押すことによってプレイヤーが弾を撃てるという新たな機能を作成したいです。そこで、その機能を実装するための新たなroomを作成し、そのroomに以下のようにdata,processを配置します。
これでプレイヤーがSPACEキーを押してプレイヤーが弾を撃つ機能が作成でき、デバッグ実行をすれば静止したプレイヤーが本当に弾を撃てるかどうかをテストすることが可能です。ここで、これまでに作成した2つのroomでそれぞれ実装した機能を合わせることにより、WASDキーで操作して移動できるプレイヤーからSPACEキーを押すことによって弾を撃てるようにしたいです。まず、最初に作成したWASDキーによるプレイヤー操作のroomを以下のように変更し、roomの出力を指定します。
これで、WASDキーによって操作され移動後のプレイヤーデータがroomの出力となります。この出力は何かというと、あるroomを実装する上でdata,processだけでなく、他のroomも配置することが可能であり、そのroomで指定した出力データを利用することができます。これにより、先ほど作成したSPACEキーを押してプレイヤーが弾を撃てるroomの中を以下のように変更します。なお、青色はroomを表しています。
これで、静止したプレイヤーではなく、WASDキーで操作して移動できるプレイヤーから弾が撃たれるようになりました。このように、今までに作成した機能(room)同士を組み合わせ、1つの大きなゲーム(mansion)を作るというのが、MansionEngineのコンセプトです。
また、もしもここでプレイヤーの操作方法や移動の挙動を変えたくなったとしても、最初に作成したWASDキーによるプレイヤー操作のroomの配置・接続やそのroomで使用されているprocessに変更を加え、デバッグ実行することにより、容易に修正とテストをすることが可能です。このように、様々な機能が作成されてゲームの開発規模が大きくなったとしても、各機能の修正とそこからの単体テスト・結合テストが容易にできるのもMansionEngineの大きな特徴です。
ここで、MansionEngineによる具体的なゲーム開発の流れの話は終わろうと思いますが、最後に、プレイヤーと接触すればプレイヤーがダメージを受ける敵や、プレイヤーと接触すればプレイヤーが回復する回復アイテムなども実装したい人がいると思います。そこで必要になるのが、当たり判定の処理ですが、MansionEngineでは当たり判定の処理も、プレイヤーデータや敵の配列データを入力データとして受け取り、当たったか否かのbool値や、当たった敵一覧を示すインデックス配列を、出力データとするprocessで実装されることを想定しています。
従来のゲームエンジンでは、当たり判定用イベント関数内部で、どのオブジェクトと当たり判定が発生したのかをオブジェクトに振り分けられたタグなどで確認しなければなりませんでしたが、MansionEngineではその必要がなくなり、さらに各データごとの当たり判定の処理順序なども開発者が明示することが可能です。これにより、複雑なコードを書く量も減らせ、さらに1フレーム間で行える処理の制約も大きく広げられることが期待できます。
現在のMansionEngine開発状況
github(https://github.com/Tokumochi/MansionEngine) 上で開発しており、ブラウザ上で開発・実行することができることを今は目指しています。
現状の開発状況として、
以下のような新たなdata,process,roomなどの新規作成・削除が行えるディレクトリ画面や、
などを実装していますが、まだまだ実装したい内容は多く、開発の道のりは長いです。
最後に
ここまで本記事を読んでくださりありがとうございました。私はゲーム開発を職業にしている人間ではないため、実際にゲーム開発を仕事にしている方や、ゲーム開発の知識・ノウハウに富んでいる方に、MansionEngineに対する意見が欲しいと思っています。もちろんそれ以外の方でもどんな意見でもコメントしていただけると嬉しいです。また、もしもMansionEngineの開発に協力していただける方がいるのであれば、めちゃくちゃ嬉しいです。