はじめに
この記事は はてなエンジニア Advent Calendar 2024 2025/1/14の記事です。
はてなエンジニア Advent Calendarといいつつ個人開発の話で恐縮なのだが……ゲームエンジン『Unity』を使ってテキストアドベンチャーゲームを作っている。
素のUnity(C#)だけでは膨大な工数がかかるので、Unityのアセット『Naninovel』を使っていた。
シナリオを改稿したり校正の反映をしていくわけだが、『この文字、豆腐にならないよな大丈夫だよな…』と心配になることがあった。
そこまで特殊な文字が多いわけじゃないし、だいたい大丈夫なわけだけど、一応チェックして大丈夫なことを担保しておきたいなと思ったので、GithubActionsでチェックできる仕組みを作った。
作ったもの
使い方等はREADME参照のこと。
『豆腐』とは
Unityにおいて文字周りの表示やスタイルは、『TextMesh Pro』という仕組みを使っている。
TextMesh Proでは事前にFontAtlasと呼ばれるテクスチャを作っておいて、そのテクスチャを使って文字描画するという仕組み。
テクスチャにない文字を描画しようとすると、文字データがなくて白い四角になってしまいます。これをいわゆる『豆腐』と呼ばれている。
基本的な仕組み
Naninovelシナリオ構文の対応
このあたりはpublicなページに書いてあるNaninovelシナリオ構文を泥臭〜くパースしている。
ラベル・スクリプト・コメントの場合はその行を扱わないとか
/**
* Naninovelのラベル構文であるかどうか
* @param line
*/
function isLabelLine(line: string): boolean {
return line.trimStart().startsWith('#')
}
/**
* Naninovelのスクリプト構文であるかどうか
* @param line
*/
function isCommandLine(line: string): boolean {
return line.trimStart().startsWith('@')
}
/**
* Naninovelのコメント構文であるかどうか
* @param line
*/
function isCommentLine(line: string): boolean {
return line.trimStart().startsWith(';')
}
rubyタグや改行タグをパースしてトリミングするとか
/**
* セリフ構文の場合に話者IDを除外してセリフ文章だけを返す セリフ構文でない場合はなにもしない
* @param line
*/
export function trimAuthor(line: string): string {
const colonIndex = line.indexOf(':')
if (colonIndex === -1) return line
return line.slice(colonIndex + 1).trim()
}
export function trimBracket(line: string): string {
return line.replace(/<[^>]*>/g, '')
}
export function trimSquareBrackets(line: string): string {
return line.replace(/\[.*?\]/g, '')
}
export function trimRuby(line: string): string {
const regex = /<ruby="([^"]*)">(.*?)<\/ruby>/g
return line.replace(regex, (_match, rubyValue, baseText) => {
return `${baseText}${rubyValue}`
})
}
正規表現系はChatGPT君に逆引きで投げて調整すると結構すぐ実装できた。
ちゃんとテストも書いててえらい!
今後やっていきたいこと
一旦エラーを出せるようになったので、ゲーム開発の方に戻るためこちらのツールの開発は小休止するが、色々やりたいことはある。
ログ周りをいい感じにしたい

今素朴にcore.infoで出しているだけなので、もっとかっこよくしたい!
Marketplaceに出す
今作っているゲームが完成したら、Marketplaceに出してみたい!
Naninovel専用でなおかつGithubActions向けなので、どのぐらいニーズが有るかは不明ではあるが、他人のニーズで開発してるわけじゃない。
yarn packageにして手元で実行できるよう
今のところはGHAで十分なので放置しているが、yarnコマンドから動かせるともっとこまめに実行できて良さそう。
おわりに
自分のための個人開発なので、ゆるく適当にやってる。releaseも結構適当なので、v0.0.0のうちはガンガン変わるかも。
ゲーム開発していると、なかなかpublicなrepositoryで出せるものが少ないけど、こういうシナリオチェック系ツールはOSSにしやすくて気分転換になる。
Steamウィッシュリスト登録よろしくね!