この資料は、「2024 年度 Ruby アソシエーション開発助成金」制度で採択された「Processing Gem ベースの 2D レトロゲームエンジンの開発」についての最終報告書になります。
昨年度採択されたCRuby 用 Processing Gem の本家 Processing との互換性向上に向けた取り組みを基に、その成果物である Processing Gem をベースにして新たに 2Dレトロゲームエンジンの開発を行いました。
このゲームエンジンは 2D のレトロゲームをターゲットとし、解像度や色数、オーディオ関連の仕様に意図的な制限を設けることでゲーム開発の複雑さを軽減し、初心者でも手軽にゲーム制作を始められる環境を提供することを目的としています。
Ruby と Processing を基盤とするこのゲームエンジンの開発により Ruby を活用したゲーム制作の幅を広げ、コミュニティの発展に貢献することを目指すものです。
本プロジェクトではレトロゲームエンジンを開発するにあたり、以下の順で開発を進めました。
- スプライトエディター
- マップエディター
- 統合環境化
- ゲーム実行機能
- オーディオ機能実装に足りてない機能を低レイヤーに実装
- サウンドエディター
ここからはそれぞれの開発内容について詳しく説明していきます。
本ゲームエンジンは 2Dレトロゲームを主なターゲットとしておりドット絵を基本としたゲーム制作を想定しています。そのため、まずはドット絵制作に特化したエディターを開発しました。
ここでは、スプライトエディターの画面を機能ごとに説明します。
スプライトページ選択
3 の「スプライト選択領域」を16ページ分保持していますので、数字横の左右ボタンで表示するページを切り替えることができます。
スプライトのサイズ選択
8、16、32 はそれぞれドットで 8x8、16x16、32x32 を表し、ドット絵編集領域を選択したサイズに変更します。またスプライト選択領域の選択枠も、選択したサイズに合わせた大きさに変わります。- スプライト選択領域
8x8 や 16x16 の大きさのスプライト画像を敷き詰めたスプライトシートを表示します。
各スプライト画像をクリックして選択するとドット絵編集領域に表示し、描画ツールで編集できるるようにします。 - ドット絵編集領域
スプライト選択領域で選択した範囲のスプライト画像を、5 の描画ツールを使って編集します。 - 描画ツール
選択ツール
ドット絵の一部を選択し、カット・コピーしたり移動したりできます
ブラシ
クリックした位置に、選択した色でドットを描画します
塗りつぶし
クリックした位置の周囲を、選択した色で塗りつぶします
直線ツール
ドラッグした始点と終点を、選択した色で直線を描画します
矩形(枠線)
ドラッグした始点と終点を矩形の左上と右下とし、選択した色で枠線を描画します
矩形(塗りつぶし)
ドラッグした始点と終点を矩形の左上と右下とし、選択した色で塗りつぶします
楕円(枠線)
ドラッグした始点と終点を楕円の左上と右下とし、選択した色で枠線を描画します
楕円(塗りつぶし)
ドラッグした始点と終点を楕円の左上と右下とし、選択した色で塗りつぶします
- カラーパレット
描画ツールで編集する際の色を選択します。
パレットの色については一旦この32色としていますが、このカラーパレットでゲームの印象がだいぶ変わるため、今後別の色セットに変更する可能性もあります。(現状は PICO-8 の作者が開発中の Picotron のカラーパレットをそのまま採用しています) - 画面配置が未決定な機能を一時的に配置
UI 設計上ではまだ検討中ですが、機能としては実装したものを一時的にウィンドウ右端に集めています。今後の開発でそれぞれ適切な場所に移動予定です。
レトロゲームのドット絵制作に必要となる基本的な機能はひととおり実装できました。
スプライトエディターとして当初予定していた基本機能は一旦実装できています。ただ、実際にゲーム開発で利用していくと欲しくなる機能がありますので、今後も継続して機能追加していく予定です。
- 左右、上下反転機能
- 曲線描画ツール
- 矩形以外の選択ツール
- レイヤー機能
- アニメーション関連機能
スプライトエディターで作成したドット絵をマップチップとして画面に配置し、RPG のフィールドやダンジョン等のマップを作成したり、横視点のプラットフォーマーゲーム向けのステージを作成する画面としてマップエディターも開発しました。
ここでは、マップエディターの画面を機能ごとに説明します。
スプライトページ選択
3 の「スプライト選択領域」を16ページ分保持していますので、数字横の左右ボタンで表示するページを切り替えることができます。
スプライトのサイズ選択
8、16、32 はそれぞれドットで 8x8、16x16、32x32 を表し、配置するマップチップの大きさを変更します。- スプライト選択領域
8x8 や 16x16 などの大きさのスプライト画像を敷き詰めたスプライトシートを表示します。
クリックで選択した部分の画像を、6 の描画ツールで 5 のマップ編集領域に配置できるようにします。
マップ選択
マップデータは複数作成することができるので、数字横の左右ボタンで表示するマップを切り替えることができます。- マップ編集領域
3 のスプライト選択領域で選択したマップチップを、6 の描画ツールで配置してマップを編集することができます。 - 描画ツール
2Dレトロゲームのマップ・ステージ制作に必要な最低限の機能をひととおり実装できました。
マップエディターは、ゲーム制作に必要な最低限の機能を実装しました。開発スケジュール的に優先度をさげた機能もいくつかありますので、今後も継続して機能追加していきたいと思っています。
- 選択ツール
- 拡大縮小機能
- レイヤー機能
- 不動スプライト統合機能(負荷軽減のため)
スプライトエディターとマップエディターを実装した時点では起動時はどちらかの画面を固定で表示し切り替えられない状態でした。しかしレトロゲーム開発の統合開発環境とするために各エディターを切り替えながら利用できるようにする必要があります。
こちらは統合環境化実装中に、実際にスプライトエディターとマップエディターを切り替えて使う様子です。
→ https://x.com/tokujiros/status/1863607102314631666
画面上部にナビゲーション用のバーを作り、そこに画面切り替えボタンを配置しました。
- エディター切り替えボタン
各画面切り替え用のツールバーを Navigator クラスとして実装しました。
ゲームエンジンを統合開発環境として設計するにあたり、ゲーム実行ボタンを押すたびにソースコードを初期状態から実行できる仕組みが必要です。このため、ゲームの実行開始時には実行環境を初期化し、前回の実行状態を引き継がないよう設計しました。具体的には、無名モジュールのインスタンスを実行コンテキストとして利用し、その中でソースコードを eval することで、各実行ごとの状態を完全に分離しています。
ゲーム実行のための画面表示や実行環境の管理機能などを、Runner クラスとして実装しました。
ソースコードは外部テキストエディターで編集することを想定していますので、ファイルが更新されたら自動で再実行、または実行状態のままコードを反映する仕組みを導入したいと思っています。これが実現できると、ゲーム開発の効率が大幅に向上するのでぜひ実現したいところです。
またゲーム実行コンテキスト分離の実装は無名モジュールを実行コンテキストとしたことの弊害で当初ユーザー定義クラス内でユーザー定義関数が呼べなかったりといくつか問題がありました。これを解決するために method_missing を活用するなど苦しい工夫で回避していますが、ここは今後 Ruby 本体に Namespace 機能が導入されれば、実行コンテキストをネームスペースで分離できるようになるのではないかと考えており、それが可能ならばシンプルに実装し直すことができるかもしれないと期待しています。
前年度に採択いただき開発した Processing Gem でひととおりの機能が揃っているグラフィックス周りとは違い、サウンドエディターとミュージックエディターの開発には事前に低レイヤーの機能追加が必要でした。
低レイヤーに実装しているオーディオ関連の機能は、サイン波や矩形波、または任意の .wav ファイルなどを鳴らすまでしかできておらず、複数の音を組み合わせて新しく効果音を作成したり、音楽を鳴らしたりする機能が足りていませんでした。
このため低レイヤー部分にシーケンサークラスを追加実装しました。
Sequencer クラスのインターフェイスはシンプルです。以下のように利用します。
seq = Sequencer.new # シーケンサーオブジェクト作成
seq.add(Oscillator.new(freq: 440), 0, 1) # 再生開始から0秒目にラの音を1秒再生
seq.add(Oscillator.new(freq: 440), 2, 0.5) # 再生開始から2秒目にラの音を0.5秒再生
seq.add(Oscillator.new(freq: 440), 4, 0.1) # 再生開始から4秒目にラの音を0.1秒再生
Sound.new(seq, 5.1).play # シーケンサーオブジェクト自体を再生
シーケンサークラスに音と時間を指定して複数追加することで、指定時間通りに音を順に鳴らすことができるようになりました。
こちらは Sequencer クラスの動作確認のため、簡易的な MML コンパイラーを実装し短い音楽を鳴らしている様子です。
→ https://x.com/tokujiros/status/1871253335141130653
C++ の低レイヤーライブラリに Sequencer クラスを実装しました。
レトロゲームに適したサウンドを制作するために、シンプルな音を組み合わせて効果音を作ることができるサウンドエディターも開発しました。
ここではサウンドエディターの画面を機能ごとに説明します。
サウンド選択
サウンドデータは複数作成することができるので、数字横の左右ボタンで表示するサウンドを切り替えることができます。
BPM 設定
BPM (Beat Per Minute) とは1分間に刻まれる拍子の数を表す数字です。サウンドの再生スピードを設定することができます。
データ編集
表示中のサウンドデータの中身を空にしたり、データ自体を削除することができます。- サウンド編集領域
横軸を時間、縦軸を音階として各波形の音符をブラシツール等で編集し、サウンドを制作することができます。
再生コントロール
編集中のサウンドを再生したり停止したすることができます。- 編集ツール
- 波形選択
ブラシツールで追加する音の音色を選択することができます。
レトロゲームのピコピコサウンドを手軽に制作することができるレベルまで実装することができました。
こちらはサウンドエディターで効果音を編集しゲーム内で鳴らす様子です。
→ https://x.com/tokujiros/status/1887935444580712721
サウンドエディターで効果音を作成するときに欲しい機能はまだありますので、今後も継続して機能追加していく予定です。
- 各音の音量の調整
- 音色の加工機能(エンベロープ、各種フィルター、LFO など)
- 選択と編集機能の強化
当初はミュージックエディターも作成する予定でしたが、サウンドエディターで再生スピードを下げると音楽を作成することができることから、ほぼ同じ UI を別画面で用意する必要があるのか疑問があるため、一旦ミュージックエディターは実装しないこととしました。
音楽制作画面のつくりとしてはいろいろあり、ピアノロールをベースとしたマウス入力中心の方式、トラッカーと呼ばれる時間軸を縦に音の情報を数値で入力する方式、MML (Music Macro Language) ベースのテキスト入力方式など、レトロゲームのチップチューンを制作するのに適したインターフェイスを検討し今後改めて実装したいと思います。
ここからはメインのゲームエンジン開発以外の成果について記載します。
このゲームエンジンでどんなゲームが作れるかを確認するため、よくあるタイプのゲームの基本部分をサンプルゲームとしていくつか制作しました。
いわゆるマリオブラザーズのような横視点で重力が下方向に向いたアクションゲームです。 1つ目のロボットがプレイヤーキャラクターで左右カーソルで移動、スペースキーでジャンプ。 トゲトゲにふれるとゲームオーバです。
ソースコードは空行とコメントを除くと 82行です。
一般的な縦シューティングゲームです。 進行方向は縦で、上から敵が来るのでカーソルキーで自機の移動とスペースキーでショットを撃ちます。
ソースコードは空行とコメントを除くと 126行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1888308304222503386
左右カーソルキーで自機を回転、上カーソルキーで加速、スペースキーで弾を撃ちます。
ソースコードは空行とコメントを除くと 106行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1888524579687309398
ユーザーの操作は無く、設置した砲台が攻撃範囲に入った敵を自動的に攻撃します。 敵は画面右端から侵入・進行し、砲台の攻撃を耐え左端まで到達されるとゲームオーバーです。 この状態ではゲーム性がゼロですが、敵を倒したらコインをゲットしそのコインで砲台を強化するなどが考えられます。
ソースコードは空行とコメントを除くと 121行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1889025712948158569
上下左右カーソルキーを押した方向にプレイヤーの向きが変わり、カーソルを押している間はプレイヤーのレースシップがジェット推進で直進します。 レースシップには慣性が働くため、減速する際には逆向きにジェットを噴射する必要があります。 スタート地点からゴールまでのタイムを競います。(作者のベストタイムは 8.183秒です)
ソースコードは空行とコメントを除くと 126行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1895666246785610226
ヴァンパイアサバイバーズという人気ゲーム風のサンプルゲームです。 カーソルキーでプレイヤーキャラクターを移動しますが、攻撃は自動で弾を撃つだけなのでプレイヤーは敵を避けることに集中します。
ソースコードは空行とコメントを除くと 159行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1895781930924462379
地面を掘って、鉱石をゲットしてスコアを稼ぐゲームです。 左右カーソルキーでプレイヤーキャラクターが移動し、スペースキーでジャンプします。 キャラクターが地面に接した方向のカーソルキーを押すと地面を掘り、金塊ブロックは三回掘ることで金をゲットすることができます。
ソースコードは空行とコメントを除くと 106行です。
実際にゲームが動いている様子 → https://x.com/tokujiros/status/1898807976049390028
1/18 の「東京Ruby会議12」でゲームエンジンについて発表しました。
発表時には、運営中の Ruby でのゲーム開発 Discord への招待リンクを設置し 13名ほど参加いただくことができました。
YouTube でサンプルゲーム開発の様子をライブ配信しました。
- 自作レトロゲームエンジンでタワーディフェンス風ゲームを作るよ
- 2時間くらいでサクッと、サバイバー系ゲームを作るよ
- 2時間くらいでサクッと、サバイバー系ゲームを作るよ 2
- 【2D ゲーム開発】地面掘る系ゲームを作るよ
残念ながらほとんど視聴されていませんが、今後本レトロゲームエンジンでのゲーム制作 Howto 動画を制作・配信し、Ruby によるゲーム開発の敷居を下げられるようにしていきたいと思っています。
ゲームエンジン自体は実用できるレベルになってきましたが、肝心のドキュメント類がまだ足りていません。ですので今後はリファレンスやチュートリアルなども作成し発信していく計画です。
ruby.wasm 対応をすることで、ゲームエンジンで作ったゲームの実行環境としてブラウザーに対応することができます。これは作ったゲームを広く手軽に遊んでもらうためにはとても大きな利点になります。特に、インストール不要でブラウザー上で即座に動作することは、ユーザーの障壁を大きく下げるため、カジュアルなプレイヤーにもリーチしやすくなります。
当初計画していた開発内容はほぼ予定通り実装することができました。これによって、目的としていた通り Ruby で手軽にゲーム開発を始められるツールが制作できました。
これからはソフトウェアとしての機能強化や環境整備を継続するとともに、利用者を増やし、Ruby によるゲーム制作人口を増やすことによって Web 開発以外の用途での Ruby 利用率を増やすことにもつなげていきたいと思います。
この成果を達成するためにサポートしてくださった Ruby アソシエーション様と、メンターとして支えてくださった須藤功平様に深く感謝いたします。


























