やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

突然ノベルゲームを作りたくなったのでツールを探してみたが超大変だった

 なんかいい感じのライブラリやツールがあるだろうと思ったのだが、微妙だった。

ライブラリを探した

 残念ながら、私の環境(ラズパイ4 ARM 32bit)に非対応だった。あるいはエラーが出て実行できなかった。

ツール 結果
ティラノスクリプト Linux非対応
Almight Linux非対応
light.vn Linux非対応
SKYNovel 成功(ブラウザでサンプルの動作を確認できた)
Suika2 失敗(Web版をローカルから実行するもPreparing...から変化せず。アップロード必須?)
吉里吉里 Linux非対応(Linux化したプロジェクトもあるようだが動作しないらしい。試すことすら面倒なのでやめた)

SKYNovel

 SKYNovelはElectronを利用したものらしい。

 以下のようなデータが使える。

種別 形式
スクリプト 拡張子sn文字コードUTF-8、改行コードLFのテキストファイル
画像 png、jpg、jpegsvg、mp4(2020/12/13時点:H265は未サポート)、スプライトシート( jsonpng(または jpeg))
音声 mp3、m4a、oggaac、webm、flac、wav(ブラウザサポート依存、アプリ版はaac非対応)
フォント woff2、otf、ttf

サンプルを動作させる

 サンプルとして配布されたゲーム用プロジェクトを動作させる。

 以下サイトに手順があるので、それに従った。もうすでに手順が膨大で面倒くさいし、Windowsベースなので嫌な予感しかしない。

1. VSCode, Node.jsをインストールする

2. サンプルプロジェクトをダウンロードする

git clone https://github.com/famibee/SKYNovel_sample

3. SKYNovel用のVSCode拡張機能をインストールする

 その手順は以下。

  1. VSCodeを起動する
  2. Ctrl+Pキーを押す
  3. ext install famibee.skynovelを入力する
  4. Enterキーを押す
  5. 拡張機能がインストールされる

4. プロジェクト初期化

  1. VSCodeのメニューを表示する
  2. ファイルフォルダーを開くでサンプルプロジェクトSKYNovel_sampleディレクトリを開く
  3. 初期化中です。ターミナルの処理が終わって止まるまでしばらくお待ちください。というダイアログが出る(約5分かかる! npmでパッケージをダウンロードしている)

ターミナル・ログ

> Executing task: cd "/tmp/work/SKYNovel_sample" ; npm i ; npm run webpack:dev <

npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.

added 722 packages, and audited 723 packages in 5m

101 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

> sn_sample@1.0.0 webpack:dev
> webpack --mode development --config ./core/webpack.config.js

asset index.js 1.99 MiB [compared for emit] (name: main)
runtime modules 1010 bytes 5 modules
cacheable modules 1.9 MiB
  modules by path ./node_modules/ 1.9 MiB
    modules by path ./node_modules/url/ 37.4 KiB
      ./node_modules/url/url.js 22.8 KiB [built] [code generated]
      + 2 modules
    modules by path ./node_modules/querystring/*.js 4.51 KiB
      ./node_modules/querystring/index.js 127 bytes [built] [code generated]
      + 2 modules
    ./node_modules/@famibee/skynovel/dist/app.js 1.85 MiB [built] [code generated]
    ./node_modules/gamepad.js/gamepad.js 13.8 KiB [built] [code generated]
  modules by path ./core/*.js 306 bytes
    ./core/app4webpack.js 288 bytes [built] [code generated]
    ./core/plugin.js 18 bytes [built] [code generated]
./core/plugin/ sync ^\.\/.*$ 160 bytes [built] [code generated]
webpack 5.72.0 compiled successfully in 13436 ms

asset web.js 1.99 MiB [compared for emit] (name: main)
runtime modules 891 bytes 4 modules
built modules 1.91 MiB [built]
  modules by path ./core/ 466 bytes
    ./core/web4webpack.js 288 bytes [built] [code generated]
    ./core/plugin.js 18 bytes [built] [code generated]
    ./core/plugin/ sync ^\.\/.*$ 160 bytes [built] [code generated]
  modules by path ./node_modules/ 1.91 MiB
    ./node_modules/@famibee/skynovel/dist/web.js 1.89 MiB [built] [code generated]
    ./node_modules/gamepad.js/gamepad.js 13.8 KiB [built] [code generated]
webpack 5.72.0 compiled successfully in 13050 ms

ターミナルはタスクで再利用されます、閉じるには任意のキーを押してください。

5. プロジェクト実行

  1. アクティビティバーの紙飛行機アイコンをクリックする
  2. サイドバーワークスペースにある起動:ブラウザ版アイコンをクリックする
  3. しばらく待つとブラウザが起動し、ゲーム画面が表示された。

 クリックすると立ち絵が出てきた。

シナリオを編集してみる

  1. VSCodeアクティビティバーにあるエクスプローラをクリックする
  2. docpjrmatmain.snをクリックする

 以下のような内容だった。

[title text='シンプルテンプレ'][call label=*init]

[add_lay layer=base class=grp]
[add_lay layer=0 class=grp]
[add_lay layer=mes class=txt]

    [call fn=ext_*]
    [call fn=face_*]

    [update_check url='https://raw.githubusercontent.com/famibee/SKYNovel_sample/master/update_tst/']

*ループ処理
    [fg fn=bg_0 layer=base]
背景表示(クリックで背景変更)、[l]

    [fg fn=bg_1 layer=base]
背景変更、[l]



    [fg layer=0 fn=face_柊24_制服 face=face_柊24_表情_口_笑顔,face_柊24_表情_目_瞬き通常,face_柊24_表情_マユゲ_通常,face_柊24_前髪 time=0]
;   [fg layer=0 fn=face_柊24_制服 face=face_柊24_表情_口_笑顔,face_柊24_表情_目_瞬き通常,face_柊24_表情_マユゲ_通常,face_柊24_前髪 time=0 visible=false]
;   [fg_fi layer=0 x=50]
;画像立ち絵、[l][r]

    [fg_squat layer=0]
立ち絵を屈伸[l][r]

    [fg_sidestep layer=0]
立ち絵を反復横跳びさせる(楽しそう)[l][r]

    [fg layer=0 fn=face_柊24_制服 face=face_柊24_表情_口_びっくり,face_柊24_表情_目_瞬き通常,face_柊24_表情_マユゲ_通常,face_柊24_前髪 time=0]
表情変化、

    [fg_shake layer=0]
立ち絵を震わせる[l][er]



    [lay layer=0 page=fore fn=clock]
時計に変更、

    [zoom_tsy layer=0 fn=clock time=2000 visible=true ease=Back.Out]
ズームイン登場、[l]

    [zoom_tsy layer=0 fn=clock time=2000 visible=false ease=Back.In]
ズームアウト退場[l]


[jump label=*ループ処理]


;********************************************************
*init
    [toggle_full_screen key=w]
    [event global=true call=true key=p label=*snapshot]
    [event global=true call=true key=F8 label=*dump cond=const.sn.isDebugger]
[return]

*toggle_full_screen
    [toggle_full_screen][return]

*set_focus
    [set_focus to=&const.sn.eventArg]
[return]

*snapshot
    [snapshot][return]

*dump
    [dump_lay]
;   [dump_val]
;   [dump_stack]
[return]

 とりあえず任意のテキストを表示したい。適当に「ここに新たなテキストを追加しちゃいます!」というテキストを表示させてみる。以下のように編集してみた。

...
*ループ処理
    [fg fn=bg_0 layer=base]
ここに新たなテキストを追加しちゃいます!
背景表示(クリックで背景変更)、[l]
...

 ファイルを保存すると、自動的にビルドがはじまった。またしても数分待たされる。つらい。テストプレイするのに途方もない時間がかかるよ、これ。

 表示された!

タグ調査

 あとは詳しい構文を把握して、思い通りに台本(スクリプトと呼ぶらしい。.sn拡張子ファイル)を書けるようになりたい。

 どうやら[fg fn=bg_0 layer=base]のようなコードをタグと呼ぶらしい。(HTMLのタグと混同するのでマクロとかにしてほしかった)その一覧が以下。

 膨大すぎる。とりあえず左のグループ名だけ列挙してみる。

  • 変数操作
  • レイヤ共通
  • トゥイーンアニメ
  • 文字・文字レイヤ
  • 画像・画像レイヤ
  • HTMLフレーム
  • イベント
  • BGM・効果音
  • 条件分岐
  • ラベル・ジャンプ
  • マクロ
  • しおり
  • 画面揺らし
  • システム
  • デバッグ・その他

 用語とその概念がわからない。クソ読みづらいドキュメントから、なんとか解読してみる。

用語 意味
レイヤ 画像や文字を描画する領域。それぞれ専用のレイヤがあり、さらにそれぞれには表裏がある。表裏はダブルバッファリングによるチラツキ防止や後述するトゥイーンアニメで用いる
HTMLフレーム HTMLのiframe要素。レイヤの手前に表示されてしまう。(これはたぶん使わないだろう)
トゥイーンアニメ レイヤやフレームに対するアニメ(場面転換の演出)
イベント マウスやキーボードのイベント処理(クリック待ちなど)
マクロ 複数のタグをまとめたもの(おそらくプログラミング言語でいうところの関数やメソッドに似た概念)

 以下は大体わかる。

用語 意味
変数 数値やテキストなどのデータを入れるもの
ラベル・ジャンプ C言語でいうgoスクリプト処理をそこへ移動する
条件分岐 if文。変数を使って比較式を書き、その真偽によってルート分岐する
用語 意味
しおり セーブデータ

 画面サイズの定義ってどうやるの? const.sn.frm.(フレーム名).widthというやつか? でもそれは<iframe>の幅サイズっぽいから違う遠思う。うーん、もしかして背景画像のサイズを使うのか? タグリファレンスにもないっぽいし、サンプルのスクリプトにもそれっぽい定義など書いてなかった。

 レスポンシブ対応は書いていないからできないのだろう……。拡大とか切り取りとか、ピクセルデータ基準で、詳細にプログラミングして設計したいのだが、そんなことはできないのだろうな。

 解読に疲れたので断念。ドキュメント超読みづらい……。

所感

 なんか、思っていたより超大変なんだが。

  • インストールに時間がかかる
  • ビルドに時間がかかる(テストプレイ大変すぎ)
  • スクリプトの記法を学習するコストが高すぎる(ドキュメントも読みづらい。概念の説明がないため文脈から推測せねばならない)

 スクリプトの例文もないため、「これでいいのかな?」と動作させながら確認せざるを得ない。なのにちょっと変更しただけで毎回ビルドが必要で、それに時間がかかる。やってらんない。これはキツイ。

 ティラノスクリプトの機能デモは超わかりやすい。実際にブラウザ上でゲームが動作するし、そのときのスクリプトがリアルタイムで表示される。これはすごい。でもラズパイで作れない……。ティラノスタジオとかいうエディタが必須なのに、WindowsMac用のアプリしかない……。

 もっと楽にできないの? WEBサイトで台本テキストを入力すると即座にブラウザでプレビューできるくらいの簡単なやつがほしいんだが。スクリプトも以下くらい簡単にしてほしい。

背景 1
立ち絵 1 表情 1
「このテキストをメッセージウインドウに表示する。」
「ウインドウいっぱいになったら自動的に次のページに分断してほしい。」
「ウインドウがいっぱいになっていなくても、別キャラが話しだしたら自動的に次のページに分断してほしい。」
「次ページに遷移するにはクリックかキー押下が必要。」
「でも大抵は中途半端な位置で次のページにまたぐと読みにくい。なので画面サイズ、文字サイズを固定し、全場面でセリフを確定させ、またぐ位置を目視確認するハメになる。超大変な作業。」
立ち絵 2 表情 1
「あたらしいキャラの登場」
「二人以上いるとき、だれがしゃべっているかわかるようにするには、どうしたらいいか。鉤括弧の前にキャラ名を書く?」
キャラ名1「うだうだ。」
キャラ名2「しのごの。」
場面転換 フェードアウト 背景 2 立ち絵 3 表情 1
キャラ名2「次の選択肢から選べ。」
* 選択肢1 :label1
* 選択肢2 :label2
* 選択肢3 :label3

:label1
キャラ名2「選択肢1を選んだ。」

:label2
キャラ名2「選択肢2を選んだ。」

:label3
キャラ名2「選択肢3を選んだ。」

 変数、条件分岐、ループもほしい。関数化したい。構造体もほしい。クラスもほしい。要件が肥大化してゆく。それではプログラミングしているのと大差ない。もっとスマートにカプセル化したい。ノベルゲーとしての要件を確認し、必要な自由度を確保しつつ、構文を平易に保つ。むずかしそう。

 画像や音声などデータの読み込みタイミングも要検討。最初に全ロードだと重すぎる。かといって実行時にロードしてもレスポンスが悪すぎる。ストリーミングAPIも考慮すべきか。

 実装するの大変すぎる。ライブラリってありがたいね。でもVSCodeやNode.js,npmが重いんだよ。もっとサクサク開発したい。とくにVSCodeでフォルダを開くと、それまで開いていたやつを消さねばならないのが嫌だ。VSCodeの画面でアクティビティバーとか普段は消したいのに、ゲーム開発するときは必要になるから表示せねばならず面倒。ブラウザからWEBアプリで編集・実行したい。だれか作ってくれ。

対象環境

$ uname -a
Linux raspberrypi 5.10.63-v7l+ #1496 SMP Wed Dec 1 15:58:56 GMT 2021 armv7l GNU/Linux