ツナサンド定食

考えていたことや読んだ本の感想、作ったもの書いたものの告知を書いていこうかなぁというブログ

NaninovelのシナリオファイルでTextmeshproの文字定義に存在しない文字がないかどうか検証するGithubActionsを作った

はじめに

この記事は はてなエンジニア Advent Calendar 2024 2025/1/14の記事です。

はてなエンジニア Advent Calendarといいつつ個人開発の話で恐縮なのだが……ゲームエンジン『Unity』を使ってテキストアドベンチャーゲームを作っている。

sandwich-kitchen.com

store.steampowered.com

素のUnity(C#)だけでは膨大な工数がかかるので、Unityのアセット『Naninovel』を使っていた。

naninovel.com

naninovel.com

シナリオを改稿したり校正の反映をしていくわけだが、『この文字、豆腐にならないよな大丈夫だよな…』と心配になることがあった。

そこまで特殊な文字が多いわけじゃないし、だいたい大丈夫なわけだけど、一応チェックして大丈夫なことを担保しておきたいなと思ったので、GithubActionsでチェックできる仕組みを作った。

作ったもの

github.com

使い方等はREADME参照のこと。

『豆腐』とは

Unityにおいて文字周りの表示やスタイルは、『TextMesh Pro』という仕組みを使っている。

docs.unity3d.com

TextMesh Proでは事前にFontAtlasと呼ばれるテクスチャを作っておいて、そのテクスチャを使って文字描画するという仕組み。

テクスチャにない文字を描画しようとすると、文字データがなくて白い四角になってしまいます。これをいわゆる『豆腐』と呼ばれている。

基本的な仕組み

Naninovelシナリオ構文の対応

このあたりはpublicなページに書いてあるNaninovelシナリオ構文を泥臭〜くパースしている。

naninovel.com

github.com

ラベル・スクリプト・コメントの場合はその行を扱わないとか

/**
 * 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君に逆引きで投げて調整すると結構すぐ実装できた。

ちゃんとテストも書いててえらい!

github.com

今後やっていきたいこと

一旦エラーを出せるようになったので、ゲーム開発の方に戻るためこちらのツールの開発は小休止するが、色々やりたいことはある。

ログ周りをいい感じにしたい

素朴すぎるエラーメッセージ

今素朴にcore.infoで出しているだけなので、もっとかっこよくしたい!

Marketplaceに出す

今作っているゲームが完成したら、Marketplaceに出してみたい!

github.com

Naninovel専用でなおかつGithubActions向けなので、どのぐらいニーズが有るかは不明ではあるが、他人のニーズで開発してるわけじゃない。

yarn packageにして手元で実行できるよう

今のところはGHAで十分なので放置しているが、yarnコマンドから動かせるともっとこまめに実行できて良さそう。

おわりに

自分のための個人開発なので、ゆるく適当にやってる。releaseも結構適当なので、v0.0.0のうちはガンガン変わるかも。

ゲーム開発していると、なかなかpublicなrepositoryで出せるものが少ないけど、こういうシナリオチェック系ツールはOSSにしやすくて気分転換になる。

Steamウィッシュリスト登録よろしくね!

store.steampowered.com