Godotでビジュアルノベルエンジンを作ってみたい

実際に作るとは言っていない

唐突に「Godotでビジュアルノベルエンジンを作りたい」と思いついたのですが、現在制作中のゲームを放り出すわけにもいかないので考えたことをアウトプットだけしてみたいと思います。

まず、ビジュアルノベルを作りたいのではなく、ビジュアルノベル”エンジン”を作りたいというのがポイントです。
最近の若い人に吉里吉里やNScripterと言って通じるかわかりませんが、ああいう類のものです。

Godotでビジュアルノベルというと「ノベルゲームウィザード」というアドオンがすでにあります。

ノベルゲームウィザード|ノベルゲームを簡単に作れるGodotアセット
ノベルゲームウィザードは、ノベルゲームを簡単に製作できるコンストラクションツールです。強力なゲームエンジンGodot上で動作し、マルチプラットフォーム対応、ノベルゲーム以外のゲームジャンルにも組み込み可能。

ただこちらはあくまでアドオンであって、Godotをある程度使える人向けです。
そうではなく、ビジュアルノベルを作りたい人が素材を用意して簡単なスクリプトを書くだけでそれを読み込んで動かしてくれるエンジンが作りたいわけです。もっと言うと本当に作りたいのはエンジン本体ではなく、動かすスクリプトの仕様の方だったりします。なのでそれだけだとGodotはあんまり関係ないです。

また、実のところビジュアルノベルですらなく、想定しているのはシナリオ分岐のないキネティックノベルです。
このあたり名称とその定義は色々と複雑なのですが、少なくとも英語圏ではVisual Novelの名称は様々なアドベンチャーゲームにも使用されていて、想定しているものとはかなり違います。

というわけで、正確には「キネティックノベル用のマークアップ言語を作りたい」でした。

私は昔からキネティックノベルが小説や漫画と並ぶレベルのエンターテインメントメディアになりうる、そうあるべきだと考えていました。
ですが実際には今の世の中では動画がメディアの頂点といった感じで、小説や漫画もネット配信のおかげか元気ですが、キネティックノベルは隅に追いやられています。
そうなった理由としては制作環境の違いが挙げられるでしょう。今や動画はスマホで撮ってスマホで編集してそのまま全世界に公開できますが、キネティックノベルには標準のデータ形式すらありません。
もしキネティックノベルに標準のデータ形式があって、ビューアに作品データをダウンロードして閲覧できるような仕組みができあがっていれば状況はもう少し違っていたのかなと思っています。
なので、その標準になるマークアップ言語を作れば今からでもキネティックノベルが躍進できるのではないかという妄想をしています。目指せW3C勧告。

とまあそんな戯言はさておき。
エンジンはともかくマークアップ言語だけならゲーム制作の合間に取り組めそうです。というか、この記事を書いていたら作りたい気持ちが強まってきたのですでにちょっと取り組み始めています。

名称はとりあえずKNML(Kinetic Novel Markup Language)としておきましょう。
ベースはXMLです。HTMLと同じような感覚でキネティックノベルが作れればだいぶ参入はしやすくなると思います。まあ今どきHTMLを手書きしている人がどれだけいるかはわかりませんが。

なるべく可読性高く、あとはタイトルや作者名といったメタデータも入れられるようにして、という感じで調べて作ってみたサンプルが以下です。

<?xml version="1.0" encoding="UTF-8"?>

<knml>
    <meta>
        <title>タイトル</title>
        <author>作者名</author>
        <description>説明文</description>
        <published>2025-01-25</published>
    </meta>
    <body>
        <scene number="1">
            <background image="background1.png"/>
            <character name="John" image="john.png" position="left"/>
            <character name="Sarah" image="sarah.png" position="right"/>
            <narration>地の文1</narration>
            <dialogue character="John">「セリフ」</dialogue>
            <narration>地の文2</narration>
            <dialogue character="Sarah">「セリフ」</dialogue>
            <narration>地の文3</narration>
        </scene>
    </body>
</knml>

それから、XMLにはスキーマという記述ルールを定めた文書も必要だそうです。XML Schemaという、それ自身XMLで書かれた文書です。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/knml"
	xmlns="http://example.com/knml" elementFormDefault="qualified">

    <!-- メタデータ情報 -->
    <xs:element name="meta">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="title" type="xs:string"/>
                <xs:element name="author" type="xs:string"/>
                <xs:element name="description" type="xs:string"/>
                <xs:element name="published" type="xs:date"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <!-- 小説本体 -->
    <xs:element name="knml">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="meta" type="xs:anyType"/>
                <xs:element name="body">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="scene" maxOccurs="unbounded" type="sceneType"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <!-- 背景情報 -->
    <xs:element name="background">
        <xs:complexType>
            <xs:attribute name="image" type="xs:string"/>
        </xs:complexType>
    </xs:element>

    <!-- キャラクター情報 -->
    <xs:element name="character">
        <xs:complexType>
            <xs:attribute name="name" type="xs:string"/>
            <xs:attribute name="image" type="xs:string"/>
            <xs:attribute name="position" type="xs:string"/>
        </xs:complexType>
    </xs:element>

    <!-- セリフ情報 -->
    <xs:element name="dialogue">
        <xs:complexType>
            <xs:simpleContent>
                <xs:extension base="xs:string">
                    <xs:attribute name="character" type="xs:string"/>
                </xs:extension>
            </xs:simpleContent>
        </xs:complexType>
    </xs:element>

    <!-- ナレーション情報 -->
    <xs:element name="narration" type="xs:string"/>

    <!-- シーンの定義 -->
    <xs:complexType name="sceneType">
        <xs:sequence>
            <xs:element ref="background" minOccurs="0"/>
            <xs:choice maxOccurs="unbounded">
                <xs:element ref="character"/>
                <xs:element ref="narration"/>
                <xs:element ref="dialogue"/>
            </xs:choice>
        </xs:sequence>
        <xs:attribute name="number" type="xs:integer"/>
    </xs:complexType>

</xs:schema>

XML自体ほぼ何もわからない状態から調べたので、間違っているところがあるかもしれないことはご了承ください。
これを叩き台として機能を追加したり整理したりしていきたいと思います。

しかし、いくらマークアップ言語を整備してもそれを正しく表示してくれるエンジンがないことには何にもなりません。
いずれ、現在のプロジェクトが一段落して情熱が残っていたら自分で作るのですが、こういうのは複数あって悪いことはないですから、誰か作ってくれないものですかね。

昨今、インターネット上にはアマチュアの小説家やイラストレーターがたくさんいます。趣味で音楽を作っている人も少なからずいます。そういう土壌はあるのですから、それらの人々が何らかの方法でマッチングして共同でキネティックノベルを作るというのは十分アリだと思っています。
なので、その制作環境を整えるために協力してくれる方がいればぜひ声をかけてください。

(追記)

上記のものから少し改良したサンプルをGitHubにリポジトリを作って置いておきました。

GitHub - ruine0213/KNML: Kinetic Novel Markup Language
Kinetic Novel Markup Language. Contribute to ruine0213/KNML development by creating an account on GitHub.

今後もゲーム制作に支障が出ない範囲で改良していきたいと思います。

以上です
ここまでお読みいただきありがとうございました。
よろしければ購読をお願いします。

購読 Pixel&Voxel

最新の投稿を見逃さないように。サインアップするとメンバー限定記事へアクセスできます。
jamie@example.com
購読