この記事は夏のブログリレー30日目の記事です。
はじめに
こんにちは。24Bのあきもです。最近めちゃくちゃ酒に強いことが発覚して不思議な気分になっています。
8月から9月にかけて1-Monthonという1ヶ月間の部内ハッカソンに参加し、1人でゲームを作りました。ゲーム開発は初めてでしたが、Tauri × React × Deno × VOICEVOXという変態構成を採用したので、それについて振り返っていきます。
1-Monthonについては他の班の記事も上がっているのでぜひ読んでいってください。
作ったもの
タイトルは『PATHFINDER』です。今回の1-Monthonのテーマが「てん」と「せん」だったので、全ての点を一度だけ通るように線で結ぶというゲームにしました。要はハミルトン路を探せってことですね。閉路でなくてもクリアになりますが、閉路が見つかるとちょっとうれしいです。

ステージは自動生成で、難易度もクリアにかかった時間などを基に上下します。

こちらからダウンロードできるので良かったら遊んでみてください。
技術選定
1-Monthonにソロ参加するモチベーションの1つに、1人なら普段は触らない技術やうまくいくか分からないことにも気軽に挑戦できるというものがあります。
今回は普段触らない技術として、以前から興味があったTauriを使ってみることにしました。とはいえWebアプリで十分なことにTauriを使うのは嫌なので、VOICEVOXによる音声合成機能をつけたゲームにすることでTauriを使うモチベーションを確保しています。Web技術でゲームを作りたくてTauriを採用したのではなく、Tauriを使うためにゲームという成果物を選択したのです。
また、僕はDenoが好きなのでフロントエンドのパッケージ管理などはDenoで行っています。はじめは無難にBunなどを使おうと思っていましたが、せっかく1人ならということでDenoにしちゃいました。Viteを使うためにnode_modules
を作る必要はありましたが、やはりformatterなどを別途入れる必要がないのは楽でいいですね。あとはdeno bundle
が超便利になってViteが不要になればnode_modules
の根絶に1歩近づくので、ぜひとも頑張ってほしいところです。
その他細かいところとして、スタイリングにはゼロランタイムCSS-in-JSライブラリのvanilla-extractを使ってみました。良さそうだなーと思って使ってみたら良かったので、良かったです(頭の悪い感想)。
実装に関して
よくわからんゲームなので1つの話題を深堀りすることができないんですが、その代わり開発中にやったことを色々雑多に書き残しておきます。
TypeScriptの自動生成
Rustで実装したコマンドはフロントエンドからTAURI_INVOKE("command_name", { ...args })
というような形式で呼べますが、これを全てのコマンドに対して手作業で書くのは安全でなく面倒なのでバインディングの自動生成はほぼ必須です。今回はTauri Spectaを利用して生成しました。執筆時点ではv2がまだbetaであり、ググるとv1の情報ばかり出てくるため苦労しましたが、一度動く状態に持っていくことができれば快適でした。
グラフの描画
グラフはバックエンドで良い感じに生成し、d3-forceでレイアウトを決めてReact Flowで描画しています。React Flow自体はフローチャートというか、情報を整然と並べて表示するのが得意なライブラリですが、頂点や辺をReactコンポーネントとして手軽に扱えるライブラリが他に見つからなかったので無理やり使いました。カスタマイズ性が非常に高く使いやすかったです。
ただ、辺が頂点に重なってしまって繋がっていないのに繋がっているように見えてしまうことがあったのでそこは改善すべき点ですね。d3-forceに頂点のサイズを考慮させたりできるんでしょうか?そこまで調べる余裕はありませんでした。

音声の合成
voicevox_coreはRustで実装されているため、サードパーティのバインディングなどに頼ることなく直接利用できます。ただし執筆時点ではcrates.ioには公開されておらず、GitHubから直接入れる必要がありました。
ライセンス上の理由から音声モデルなどは別途取得する必要があるので、usage.mdに従ってダウンロードします。実装に関してはAPIドキュメントに例があるので、それに従うだけで簡単に合成できました。
キャラクターによってVVMファイルの名前が異なるのでそこだけ注意が必要ですが、対応表がVOICEVOX/voicevox_vvmのREADME.mdにあります。ちなみにこのゲームでは猫使ビィを採用しました。かわいい。
ノベルパート
キャラクターのセリフを表示するために簡易的なノベルパートを実装する必要がありました。Copilotくんがinkjsを勧めてきたので試してみましたがうまく動かず、その時点で最終発表の3日前ぐらいになっていたのでinkjsを使うのは諦めてGeminiに実装させました。少しでも条件分岐などを入れるならinkjsを使ったほうが良いのかなとは思います。
余談ですが、「inkjs react」などでググるとターミナルでの描画にReactを使うためのvadimdemedes/inkに関する情報ばかり出てくるのでググラビリティが終わっています。
結果
テーマ「せん」の方でテーマ賞を頂くことができました。ハッカソンなどでの受賞は初めてなので嬉しいです。なんでも賞品は扇子だとか。センスいいですねー。
ちなみに「てん」の方の賞品は謎の天然石ガチャです。ぶっちゃけかなり欲しかった
おわりに
今回はシンプルなゲームだったので耐えましたが、ゲームを作るのが目的なら大人しくゲームエンジンを使ったほうが良いと思います。それはそれとしてTauriはいいぞ!Denoもいいぞ!!
ソースコードはGitHubで公開しているので、もし似たようなことをしたい方がいたら参考にしてもらえると嬉しいです。
明日の投稿者は@mutv625です。わくわく!