# Naninovel スクリプト

Naninovelスクリプトはテキストドキュメント( .nani拡張子)であり、シーンで発生する動作を制御します。スクリプトアセットはコンテキストメニュー Create -> Naninovel -> Naninovel Script で作成できます。組み込みの ビジュアルエディター か、メモ帳、TextEdit、Atom などの任意のテキストエディターで開いて編集できます。

naninovelスクリプトの各行はステートメントを表し、コマンド、一般テキスト、ラベル、またはコメントになります。ステートメントのタイプは、行の先頭に置かれているリテラルによって決まります:

リテラル ステートメントのタイプ
@ コマンド
# ラベル
; コメント

上記のリテラルのいずれも行の先頭にない場合、一般テキストステートメントと見なされます。

# コマンドライン

行が @ リテラルで始まる場合、その行はコマンドステートメントと見なされます。コマンドは、シーンで起きることを制御する単一の操作を表します。たとえば、背景の変更、キャラクターの移動、別のnaninovelスクリプトの読み込みに使用できます。

# コマンド識別子

コマンドリテラルの直後には、コマンド識別子が必要です。これはコマンドを実装する C# クラスの名前か、コマンドのエイリアス(CommandAlias 属性を介して適用された場合)のいずれかになります。

たとえば、 @save コマンド(ゲームのオートセーブに使用)は、C# クラス AutoSave を介して実装されます。実装クラスにも [CommandAlias("save")] 属性が適用されているため、スクリプトで @save ステートメントと @AutoSave ステートメントのどちらでもこのコマンドを呼び出すことができます。

コマンド識別子は大文字と小文字を区別しません。次のステートメントはすべて有効で、同じ AutoSave コマンドを呼び出します:

@save
@Save
@AutoSave
@autosave

# コマンドパラメーター

ほとんどのコマンドには、コマンドの効果を定義するパラメーターがいくつかあります。パラメーターはコマンドリテラルの後に定義される、コロン(:)で区切られたKey-Value論理式です。パラメーター識別子(キー)は、コマンド実装クラスの対応するパラメーターフィールドの名前または、パラメーターのエイリアス( CommandParameter 属性の alias プロパティで定義されている場合)のいずれかです。

@commandId paramId:paramValue

@hideChars コマンドを考えてみましょう。このコマンドは、シーンに表示されているすべてのキャラクターを非表示にします。次のように使用できます:

@hideChars

time 少数 パラメーターを使用して、キャラクターがフェードアウトして完全に非表示になる(シーンから削除される)までの時間を制御できます:

@hideChars time:5.5

これはキャラクターをシーンから消すのに、5.5秒かけてフェードアウトします。

また、wait Boolean パラメーターを使用して、次のコマンドをすぐに実行するか、現在のコマンドの完了を待つかを指定できます:

@hideChars time:5.5 wait:false
@hidePrinter

上記は、文字がフェードアウトし始めた直後にテキストプリンターが非表示になります。waittrue または指定されていなければ、プリンターは @hideChars が完了してから非表示になります。

# パラメーター値タイプ

コマンドパラメータに応じて、次の値タイプのいずれかになります:

タイプ 説明
String 単純なテキスト値。例: LoremIpsum。スペースを含む場合は必ずダブルクオーテーションで括ってください。例: "Lorem ipsum dolor sit amet."
Integer 分数ではない数値、整数。例: 1, 150, -25
Decimal 小数をドットで区切った10進数。例: 1.0, 12.08, -0.005
Boolean 2つのうちいずれかを持つことができる: true または false (大文字小文字を区別しません)
Named<> 上記のタイプのいずれかの値に関連付けられた名前文字列。名前の部分はドットで区切ります。 Named<Integer> の例: foo.8, bar.-20
List<> 上記のタイプのいずれかの値をコンマで区切ったリスト。List<String> の例: foo,bar,"Lorem ipsum.", List<Decimal> の例: 12,-8,0.105,2

# 無名パラメーター

ほとんどのコマンドには、無名パラメーターがあります。名前を指定せずに使用できるパラメーターは、無名と見なされます。

たとえば、@bgm コマンドは、再生する音楽トラックの名前を無名パラメーターで指定しています。

@bgm PianoTheme

ここでの "PianoTheme" は、"BgmPath" String パラメータの値です。

コマンドごとに存在する無名パラメーターは1つだけで、他は常にパラメーターの前に指定する必要があります。

# 任意と必須のパラメーター

ほとんどのコマンドパラメーターは 任意 です。これは、事前定義された値があるか、コマンドを実行するために値を必要としないためです。たとえば、パラメーターを指定せずに @resetText コマンドを使用すると、デフォルトのプリンターのテキストがリセットされますが、次のように特定のプリンターIDを設定することもできます: @resetText printer:Dialogue

パラメーターのいくつかは 必須 で、コマンドを実行するには、常に指定する必要があります。

# コマンド API リファレンス

現在利用可能なすべてのコマンドの一覧と、概要、パラメーター、および使用例については、コマンド API リファレンス を参照してください。

# 一般テキスト

大量のテキストを含むスクリプトを快適に作成するには、一般テキストラインを使用します。先頭が事前定義されたステートメントリテラルでなければ、行は一般テキストステートメントと見なされます。

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

話者のIDをコロン (:)で区切られた一般テキストの先頭に指定して、表示テキストをキャラクターアクターに関連付けることができます:

Felix: Lorem ipsum dolor sit amet, consectetur adipiscing elit.

表示テキストに関連付けられているキャラクターの外観を常に変更したいときは、話者のIDの後に外観を指定して入力を簡略化することもできます。

Felix.Happy: Lorem ipsum dolor sit amet.

上記の行は以下の2行と同じ意味です:

@char Felix.Happy wait:false
Felix: Lorem ipsum dolor sit amet.

# コマンドのインライン化

テキストメッセージを表示中、特定の文字の直後または直前にコマンドを実行したい場合があります。たとえば、特定の単語が表示されたときにアクターの外観(表現)を変更したり、表示メッセージの中のイベントに反応して特定の効果音が再生されるなど。コマンドのインライン化機能により、このようなケースを処理できます。

中括弧([,]) を使用して、一般テキストにコマンド (組み込みカスタムどちらも) を挿入(インライン化)することができます:

Felix: Lorem ipsum[char Felix.Happy pos:0.75 wait:false] dolor sit amet, consectetur adipiscing elit.[i] Aenean tempus eleifend ante, ac molestie metus condimentum quis.[i][br 2] Morbi nunc magna, consequat posuere consectetur in, dapibus consectetur lorem. Duis consectetur semper augue nec pharetra.

インライン化されたコマンド構文はまったく同じですが、 @ リテラルが省略され、コマンド本体が角括弧で囲まれていることに注意してください。基本的に、任意のコマンドラインを使って一般テキストにインライン化することができます。効果は全く同じですが、テキストメッセージ内の位置によって異なるタイミングで行われます。

内部では、一般テキストは、インラインインデックスで識別される個々のコマンドにパースされます。 テキストは @print コマンドで表示されます。たとえば、次のnaninovelスクリプトの一般テキスト:

Lorem ipsum[char Felix.Happy pos:75 wait:false] dolor sit amet.

— は、実際には個々のコマンドのシーケンスとしてエンジンで処理されます:

@print "Lorem ipsum" waitInput:false
@char Felix.Happy pos:75 wait:false
@print "dolor sit amet."

一般テキスト上で角括弧を実際に表示するには、バックスラッシュでエスケープします。 例:

Some text \[ text inside brackets \]

— は、ゲーム内で "Some text [ text inside brackets ]" を表示します。

# ラベル

ラベルは、@goto コマンドでnaninovelスクリプトをジャンプするときに"アンカー"として使用されます。 ラベルを定義するには、行の先頭に # リテラルを記述し、ラベル名を続けます:

# Epilogue

@goto コマンドでその行にジャンプできます:

@goto ScriptName.Epilogue

指定先のラベルと同じスクリプト内から @goto コマンドを使用する場合は、スクリプト名を省略できます:

@goto .Epilogue

# コメント

セミコロン (;) で始まる行は、コメントとみなされます。コメント行は、スクリプトが解析されるときエンジンで完全に無視されます。コメント行を使用して、naninovelスクリプトを使用する自分や他のチームメンバーに、メモまたは注釈を追加できます。

; 次のコマンドはゲームをオートセーブします。
@save

# 条件分岐

スクリプトはデフォルトでは順番に実行されますが、すべてのコマンドでサポートしている if パラメーターを使用して分岐を導入できます。

; `level`の値が数値かつ、9000より大きい場合は、選択肢を追加。
@choice "It's over 9000!" if:level>9000

; `dead` 変数が bool かつ `false` の場合は、プリントコマンドを実行。
@print text:"I'm still alive." if:!dead

; `glitch` が bool かつ `true` または1~10のランダム関数の場合、
; 5以上を返し、`@spawn` コマンドを実行する。
@spawn GlitchCamera if:"glitch || Random(1, 10) >= 5"

; `score` 値が7~13の間または `lucky` 変数が bool かつ`true` の場合、
; `LuckyEnd` スクリプトを読み込む。
@goto LuckyEnd if:"(score >= 7 && score <= 13) || lucky"

; インラインコマンドで条件を記述することもできます。
Lorem sit amet. [style bold if:score>=10]Consectetur elit.[style default]

; 式自体の中でダブルクオーテーションを使用する場合、
; 必ずダブルエスケープしてください。
@print {remark} if:remark=="Saying \\"Stop the car\\" was a mistake."

@if @else @elseif @endif コマンドで、複数行に条件分岐を記述することもできます。

@if score>10
	Good job, you've passed the test!
	@bgm Victory
	@spawn Fireworks
@elseif attempts>100
	You're hopeless... Need help?
	@choice "Yeah, please!" goto:.GetHelp
	@choice "I'll keep trying." goto:.BeginTest
	@stop
@else
	You've failed. Try again!
	@goto .BeginTest
@endif

このタブは完全に任意で、可読性のためだけに使用しています。

一般テキストで同じことをします:

Lorem ipsum dolor sit amet. [if score>10]Duis efficitur imperdiet nunc. [else]Vestibulum sit amet dolor non dolor placerat vehicula.[endif]

条件式のフォーマットと使用可能な演算子の詳細については、スクリプト表記 ガイドを参照してください。

# ビジュアルエディター

ビジュアルスクリプトエディターを使用して、naninovelスクリプトを編集することができます。スクリプトアセットを選択すると、ビジュアルエディターが自動的にインスペクターウィンドウで開きます。

スクリプトに新しい行を追加するには、行を挿入したい場所を右クリックするか、 Ctrl+Space を押して(入力コンフィグメニューでデフォルトのキー紐付けを変更できます)、目的の行またはコマンドの種類を選択します。行を並べ替えるには、番号ラベルを使用してドラッグします。行を削除するには、行を右クリックして "Remove" を選択します。

ビジュアルエディターを使用してスクリプトを変更すると、インスペクターヘッダーのスクリプト名の上にアスタリスク (*) が表示されます。つまりアセットが dirty なので保存する必要があります。 Ctrl+S を押してアセットを保存します。スクリプトが dirty の時に別のアセットを選択しようとすると、ダイアログウィンドウがポップアップ表示され、変更を保存または元に戻すことができます。

編集したスクリプトを外部で更新すると、ビジュアルエディターに自動的に同期されるため、テキストエディターとビジュアルエディターの両方でスクリプトをシームレスに操作できます。もし自動同期が動いていないようなら、Unity エディターメニューの Edit -> Preferences -> GeneralAuto Refresh が有効になっているか確認してください。

プレイモード中、ビジュアルエディターで現在再生中のスクリプトラインを追跡し、ラインを右クリックして再生を巻き戻すことができます。この機能では、スクリプトに同じリソースID(リソースマネージャーメニューで割り当てられている場合)とアセット名が必要です。

再生中のラインは緑色でハイライトされます。ユーザーの入力を待つ間スクリプトの再生が停止すると、再生されたラインが黄色でハイライトされます。

エディターの動作と見た目は、スクリプトコンフィグメニューで調整できます。

# スクリプトグラフ

大量のスクリプトや非連続ストーリーを扱う場合、ストーリーフローを視覚的に表現できると便利です。スクリプトグラフツールはこのような時に便利です。

グラフウィンドウは、Naninovel -> Script Graph エディターメニューで開きます。必要に応じて、ウィンドウを他のエディターパネルと同じようにドッキングできます。

エディターリソース (Naninovel -> Resources -> Scripts) で割り当てられたすべてのnaninovelスクリプト(ノードとして表される)と、その繋がりを自動的にグラフとして構築します。

繋がりは、@goto コマンドと @gosub コマンドに基づいて生成されます。コマンドに条件式が割り当てられている場合(if パラメーター)、ノードの対応するポートが黄色でハイライトされ、ポートにカーソルを合わせると式が表示されます。

ノードをダブルクリックするか、ポートをクリックして、スクリプトアセットを選択し、ビジュアルエディターを開くことができます。ポートをクリックすると、ビジュアルエディターがラベルの行にスクロールされます(ラベルが指定されている場合)。

必要に応じてノードを再配置でき、グラフウィンドウを閉じるかUnityを終了すると、ノードの位置が自動保存されます。ウィンドウを再び開くと、位置が復元されます。"Save" ボタンをクリックして手動で保存することもできます。"Auto Align" ボタンをクリックすると、すべての位置がリセットされます。

スクリプトを変更したり、新しいスクリプトを追加したりする場合は、 "Rebuild Graph" ボタンをクリックして同期します。

# ホットリロード

プレイモードで、(ビジュアルエディターと外部エディターの両方で)スクリプトを編集し、ゲームを再起動せずに変更をすぐに適用することができます。 この機能はスクリプト設定の Hot Reload Scripts プロパティで制御され、デフォルトで有効になっています。

現在再生中のラインの前にラインを変更、追加、または削除するとき、状態の不整合を防ぐために、自動的に変更されたラインにステートのロールバックが行われます。

もしホットリロードが機能しないようなら、Auto Refresh が有効になっていて、Script Changes While PlayingRecompile And Continue Playing にセットされているか確認してください。どちらもUnity エディターメニューの Edit -> Preferences -> General にあります。

再生中のnaninovelスクリプトのホットリロードを手動で開始するには(たとえば、Unityプロジェクトの外部でスクリプトファイルを編集している場合)、 reload コンソールコマンドを使用します。このコマンドはエディターのみで機能します(ビルドでは機能しません)。

# IDE サポート

構文のハイライト、エラーチェック、オートコンプリート、インタラクティブドキュメントといったIDE機能で、スクリプト作成時の生産性が大幅に向上します。無料でオープンソースの Atom エディター(Windows、MacOS、Linuxで利用可能)用の拡張機能を作成しました。これは、NaniScript構文に不可欠なIDEサポートを提供します。

拡張機能を使うには:

  1. Atom エディター をインストール
  2. language-naniscript 拡張機能をインストール
  3. atom-ide-ui 拡張機能をインストール(拡張機能で一部の機能を提供するために必要です)
  4. Atom エディターを再起動
  5. naninovelスクリプトでフォルダーを開く(単一のファイルを開いても拡張機能はアクティブになりません)

拡張機能のアクティベートと利用に関しては、次のビデオチュートリアルを確認してください。

将来的に他のエディターのサポートも可能です。詳細は GitHub の issue をご確認ください。

# スクリプトデバッグ

大きなnaninovelスクリプトで作業しているとき、特定の部分の機能を確認するのに、常に最初からスクリプトを再生するのは面倒かもしれません。

開発コンソール で、現在再生中のスクリプトを任意の行に瞬時に「巻き戻す」ことができます:

rewind 12

— 現在のスクリプトの12行目から再生を開始します。同じ方法で前後に巻き戻すことができます。ゲームの実行中にコンソールを開くには、コンソールがエンジンコンフィグで有効になっていることを確認し、 ~ キーを押します(構成で変更可能)。タッチスクリーンデバイスで実行している場合は、マルチタッチ(3つ以上の同時タッチ)を行ってください。

現在再生中のスクリプトとラインを確認するには、デバッグウィンドウを使用します: 開発コンソールで debugと入力し、Enter キーを押してウィンドウを表示します。

Scripts Debug

再生中のスクリプト名、行番号、コマンド(インライン)インデックスがウィンドウのタイトルに表示されます。自動アテレコ 機能が有効の場合は、対応するボイスクリップの名前も表示されます。タイトルをドラッグすることでウィンドウの位置を変更できます。"Stop" ボタンはスクリプトの実行を停止します。スクリプトプレーヤーが停止すると、 "Play" ボタンで実行を再開できます。 "Close" ボタンを押すとデバッグウィンドウを閉じることができます。

デバッグウィンドウは、エディタービルドとプレーヤービルドの両方で使用できます。

最終更新 日: August 5, 2020