ScenarioFlowでは、会話シーンの内容をシナリオスクリプトに記述し、それを会話システムで実行することでその会話シーンが再生されます。SFTextは、ScenairoFlowが提供する標準的なシナリオスクリプトです。
今回の記事では、SFTextの文法と、スクリプトの快適な編集を可能にするVisual Studio Code (VSCode) の拡張機能について学びます。
はじめに
SFTextとは
SFTextは、「読みやすく書きやすい」をコンセプトにした、ScenarioFlowで使用できるシナリオスクリプトの形式の一つです。本物の台本のような見た目を持ち、シンプルな文法を持つことを特徴としています。また、Visual Studio Code (VSCode) の拡張機能で提供される、シンタックスハイライトや入力補完といった機能により、快適にスクリプトを編集することができます。
VSCodeの拡張機能の導入
Visual Studio Code (VSCode)は、Microsoftが提供するオープンソースのソースコードエディタです。VSCodeで使用できる、SFTextを快適に編集するための拡張機能が公開されています。
まずはVSCodeをインストールし、次にSFText Extension Packを導入しましょう。
VSCode:
SFText Extension Pack:
また、オプションですが、VSCodeのカラーテーマとしてAyuを使用することをお勧めします。
プログラムの準備
サンプルプロジェクトのインポート
以下のUnity Packageファイルに、今回使用するプログラムやオブジェクトが含まれています。ファイルをダウンロードして、Unityへインポートしてください。また、ScenarioFlowとUniTaskのインポートも必要なことに注意してください。
Unity Packageファイルに含まれているhow-to-write-SFText
シーンを開き、プレイモードを開始します。すると、SFTextスクリプト、Story.sftxt
が実行され、会話シーンが再生されます。ここで再生される会話シーンは、キャラクターのセリフの表示とキャラクター画像の変更、2択の選択肢によるシナリオ分岐を含む、シンプルなものです。Nextボタンを押して、会話シーンを進めます。
サンプルプロジェクトの概要
サンプルプロジェクトに含まれるクラスと、それらの役割を以下に示します。
クラス | 役割 |
---|---|
ScenarioManager | 他のクラスを統括するマネージャクラス |
ButtonNotifier | Nextボタンを押して会話シーンを進める機能を実装する |
CancellationTokenDecoder | CancellationToken 型用のデコーダを実装する。 |
PrimitiveDecoder | string 型用のデコーダを実装する |
SpriteProvider | Sprite 型用のデコーダを実装する |
CharacterAnimator | キャラ画像の変更処理を実装する |
DialogueWriter | セリフ表示の処理を実装する |
ScenarioBranchMaker | シナリオ分岐処理を実装する |
これらのクラスで構築される会話システムでは、次のコマンドを使用できます。
コマンド | 実行される演出 | 実装クラス |
---|---|---|
write dialogue async | セリフを表示する | DialogueWriter |
write dialogue and image async | セリフを表示すると同時にキャラクター画像を徐々に変更する | DialogueWriter |
change character image async | キャラクター画像を徐々に変更する | CharacterAnimator |
change character image | キャラクター画像を即座に変更する | CharacterAnimator |
show two selections async | 二つの選択肢を表示し、回答によってシナリオを2方向に分岐させる | ScenarioBranchMaker |
jump to label | 指定したラベルへシナリオを分岐させる | ScenarioBranchMaker |
これを踏まえて、Story.sftxt
と、実行される会話シーンの対応関係を確認してみてください。
SFTextの文法
基本ルール
SFText書くにあたり、まずは2つの原則を確認しましょう。
- すべての行は、縦線「|」により3つの領域に分割される
- SFTextは、複数の「スコープ」から構成される
まず、外見上の大きな特徴として、SFTextはすべての行が縦線によって区切られ、以下の3つの領域に分割されます。
領域 | 何を記述するか |
---|---|
スコープ宣言部 | スコープを開始するためのシンボルを記述する |
コンテンツ記述部 | パラメータなど、スコープの内容を記述する |
コメント記述部 | コメントを記述する(会話シーンに影響しない) |
スコープ宣言部 | コンテンツ記述部 | コメント記述部
SFText次に、SFTextは「スコープ」と呼ばれる基本ブロックで構成され、記述されたスコープが上から順に読み込まれます。
スコープには、以下の4つの種類があります。
スコープ | 役割 |
---|---|
コマンドスコープ | コマンド呼び出しを引き起こす |
セリフスコープ | セリフを表示するためのコマンド呼び出しを引き起こす |
マクロスコープ | コマンド・セリフスコープの補助をする |
コメントスコープ | コメントを記述する(会話シーンに影響しない) |
Story.sftxtにおけるスコープの分類を示します。
上の表に示されている通り、SFTextでは、コマンドスコープとセリフスコープがコマンド呼び出しを引き起こします。ScenarioFlowではコマンド呼び出しの繰り返しによって会話シーンが再生されるということを踏まえると、SFTextで会話シーンを記述するためのするべきことは、コマンドスコープとセリフスコープを適切に並べ、必要に応じてマクロスコープを添えることであるといえます。
SFTextを書くためには、最低限、各スコープについて理解する必要があります。そこで次のセクションからは、順番に各スコープの役割と書き方を詳しく見ていきます。
コマンドスコープ
コマンドスコープは、任意のコマンドを呼び出すスコープで、SFTextの核となるスコープです。以下の規則に従って記述します。
- スコープ宣言部に
$(トークンコード)
を記述してコマンドスコープを開始する - スコープを開始した行のコンテンツ記述部に、呼び出すコマンド名を記述する
- スコープを開始した行の次の行から、コンテンツ記述部にトークンコード以外のパラメータを記述する
- パラメータ記述では、
{}
で囲まれた部分のみがパラメータとして認識され、それ以外のテキストはコメントとして無視される
$tokencode | command name |
| comment {arg1} comment {arg2} comment |
| {arg3} {arg4} {arg5} ... |
SFText以下の例では、change character image async
というコマンドにトークンコードparallel
を指定し、他にパラメータとしてsmile
を与えて呼び出しています。
$parallel | change character image async |
| Change the icon to {smile} |
SFTextまた、非同期コマンドに対しては必要なトークンコードを指定しますが、同期コマンドに対しては$sync
としなければならないことに注意してください。
$tokencode | asynchronous command |
| {arg1} {arg2} ... |
$sync | synchronous command |
| {arg1} {arg2} ... |
SFTextトークンコードと非同期コマンド
コマンドには、処理が即座に完了する同期コマンドと、処理の完了に時間がかかる非同期コマンドがあります。セリフの表示やキャラクターのアニメーションなど、会話シーンでは非同期コマンドが多く使用されますが、プログラム内の設定値の変更を素早く切り替えたいときなどは、同期コマンドが便利に使用できます。
トークンコードは、非同期コマンドの実行方法を切り替えるためのパラメータです。例えば、非同期コマンドはその実行途中に処理をキャンセルすることができますが、standard
をトークンコードとして指定するとそのようなキャンセルが許可されるという性質が、promised
を指定すると一切のキャンセルが禁止されるという性質が、非同期コマンドに付与されます。これらは、コマンドの仕様、もしくはコマンドによって引き起こされる演出の重要度によって使い分けます。例えば、プレイヤーに選択肢を表示するコマンドの場合、選択肢は必ず選択されなければならないのでキャンセルは必ず禁止しなければなりませんが、セリフを表示するコマンドの場合、キャンセルを許可してセリフの読み飛ばしを許可するべきか、キャンセルを禁止して必ず全文を読ませるべきかはそのセリフの重要度次第です。
トークンコードの活用方法については、別の記事で取り扱います。ここでは、以下の2点を覚えておいてください。
- トークンコードで非同期コマンドの振る舞いを変更できる
- 同期コマンドにはトークンコードが必要ないので、SFTextで同期コマンドを呼び出す場合は
sync
を指定する必要がある
セリフスコープ
ScenarioFlowでは、コマンド呼び出しの繰り返しによって会話シーンが再生されるので、セリフの表示も、それに対応するコマンド呼び出しによって実現する必要があります。このようなコマンドの呼び出しはコマンドスコープによって記述することもできますが、SFTextでは見やすさとセリフ表示の頻度の高さを考慮して、セリフを表示するコマンド呼び出し専用の構文を用意しています。それがセリフスコープです。
セリフスコープを記述する際は、以下の規則に従います。
- スコープ宣言部にキャラクター名を記述してセリフスコープを開始する
- スコープを開始したその行から、コンテンツ記述部にセリフの内容を記述する
- 呼び出すコマンドと与えるトークンコードは、マクロスコープで指定する
キャラ名 | セリフの内容 |
SFText重要なのは、「セリフスコープは、コマンドスコープの省略記法に過ぎない」ということです。記述されたコマンドスコープは、マクロスコープ、#command
と#token
でそれぞれ指定されたコマンド名とトークンコードをもとに、等価なコマンドスコープに置き換えられます。以下に例を示します。
#command | {write dialogue async} | <-- コマンドを指定
#token | {$standard} | <-- トークンコードを指定
Sheena | Hello, I'm Sheena. | <-- セリフスコープ
| |
$standard | write dialogue async | <-- 等価なコマンドスコープ
| {Sheena} {Hello, I'm Sheena.} |
SFText上の例からわかる通り、セリフスコープで使用されるコマンドは、第一引数として話者名を受け取り、第二引数としてセリフ内容を受け取ることを想定したものでなければなりません。
さて、最も単純なセリフスコープは、すでに紹介された3つの規則に従って書くことができますが、セリフスコープをより効率的に使用するため、次の2つの規則も覚えておきましょう。
- 複数行を横断してセリフを記述でき、その場合は、各行のテキストは
<bk>
によって結合される - コンテンツ記述部を
-->
で始めることで、追加のパラメータを与えることができる。パラメータの記述方法はコマンドスコープと同じ
順に、詳しく見ていきます。
複数行に記述されたセリフの結合
まず、セリフスコープにはセリフを複数行にまたがって記述することができ、その場合、記述されたテキストは<bk>
(line breakを表す)によって結合されます。以下の例を確認しましょう。
#command | {write dialogue async} | <-- コマンドを指定
#token | {$standard} | <-- トークンコードを指定
Sheena | I'm a ScenarioFlow instructor. | <-- セリフスコープ
| Nice to meet you! |
| |
$standard | write dialogue async | <-- 等価なコマンドスコープ
| {Sheena} {I'm a ScenarioFlow instructor.<bk>Nice to meet you!} |
SFText結合されたテキストは引数としてコマンド呼び出し時にデコーダに渡され、その後にコマンドに渡されるので、デコーダ内やコマンド内で<bk>
を好きな文字に置き換えることができます。置き換える文字は、要求に応じて空白でもいいですし、改行文字でもいいでしょう。以下のコードは、複数行に書かれたセリフは改行とみなすデコーダの例です。ScenarioFlow.Scripts.SFText
名前空間に定義されるSFText.LineBreakSymbol
にシンボル<bk>
が保持されており、それを使用できます。
using ScenarioFlow.Scripts.SFText;
[DecoderMethod]
public string ConvertToString(string input)
{
return input.Replace(SFText.LineBreakSymbol, "\n");
}
C#追加パラメータ付きセリフスコープ
セリフスコープで使用されるもっとも単純なコマンドは、話者名、セリフの内容、トークンコードに対応する3つの引数を受け取ります。しかし、実践的には、それら以外のパラメータをセリフとともに指定したいことがあります。例えば、キャラクターの画像をセリフとともに指定して、セリフの表示とともに画面上のキャラクター画像を変更したい場合です。
セリフスコープでは、コンテンツ記述部を-->
で始めることで追加のパラメータを渡すことができます。パラメータの記法は、コマンドスコープの場合と同じで、{}
で囲まれたものだけがパラメータとして認識され、またパラメータは複数行に記述できます(パラメータを記述するすべての行は、-->
で始まる必要があります)。また、追加のパラメータを指定したセリフスコープは追加のパラメータを持たない通常のセリフスコープとは異なり、呼び出すコマンドは#xcommand
マクロスコープで指定します(#token
は共通)。
以下に、例を示します。-->
が一つの右矢印「→」のように表示されているかもしれませんが、実際は半角ハイフン「-」二つに大なり記号「>」がついています。
#xcommand | {write dialogue and image async} | <-- コマンドを指定
#token | {$standard} | <-- トークンコードを指定
Sheena | So, let's learn about SFText today. |
| --> Change the icon to {normal} |
| |
$standard | write dialogue and image async | <-- 等価なコマンドスコープ
| {Sheena} {So, let's learn about SFText today.} |
| {Smile} |
SFText追加パラメータを持たないセリフスコープと持つセリフスコープを区別するとき、前者を「標準セリフスコープ」、後者を「拡張セリフスコープ」と呼びます。標準セリフスコープと拡張セリフスコープは混在可能なので、状況によって使い分けると良いでしょう。
#command | {write dialogue async} |
#xcommand | {write dialogue and image async} |
#token | {$standard} |
Sheena | Don't say that! |
Sheena | You will find it helpful. |
| --> Change the icon to {smile} |
SFTextマクロスコープ
マクロスコープは、コマンドスコープとセリフスコープを補助するスコープです。マクロスコープには5つの種類があり、いずれも以下の規則に従って記述します。
#(マクロ名)
をスコープ宣言部に記述して、マクロスコープを開始する- スコープが開始した行から、コンテンツ記述部にパラメータを記述する。パラメータの書き方は、コマンドスコープと同じで
{}
に囲まれたテキストのみがパラメータとして認識される
#(macro-name) | comment {Arg1} comment {Arg2} comment .... |
SFText順に、各マクロスコープの役割と使い方を見ていきましょう。
#commandマクロスコープ
#command
マクロスコープでは、追加引数なしの標準セリフスコープで使用するコマンドを指定します。
#command | {command name} |
SFText一度宣言した#command
は、新たな#command
で上書きされるまで有効です。
#command | {write dialogue async} |
#token | {$standard} |
Sheena | Hello, I'm Sheena. | <-- 'write dialogue async' を使用
Sheena | I'm a ScenarioFlow instructor. | <-- 'write dialogue async' を使用
| Nice to meet you! |
#command | {update diaogue async} |
Sheena | Are you interested in SFText? | <-- 'update dialogue async' を使用
SFText#xcommandマクロスコープ
#xcommand
マクロスコープは、追加引数ありの拡張セリフスコープで使用するコマンドを指定します。
#xcommand | {command name} |
SFText一度宣言された#xcommand
は、新たな#xcommand
に上書きされるまで有効です。
#tokenマクロスコープ
#token
マクロスコープは、セリフスコープで使用するトークンコードを指定します。このマクロスコープで指定したトークンコードは、標準・拡張セリフスコープの両方で使用されます。
#token | {token code} |
SFText一度宣言された#token
は、新たな#token
に上書きされるまで有効です。
#labelマクロスコープ
#label
マクロスコープは、シナリオ分岐を実装するためのマクロスコープです。パラメータには、ラベル名を指定します。
#label | {label name} |
SFText#label
マクロスコープを宣言すると、その下にあるコマンドスコープもしくはセリフスコープにラベル名が付与されます。すると、C#スクリプト側からそのラベルを参照し、シナリオ分岐を実装することができるようになります。このC#でのシナリオ分岐の実装方法については、別の記事で取り扱います。
$f-promised | show two selections async |
| {Yes} |
| --- Jump to {Ans1} |
| {No} |
| --- Jump to {Ans2} |
#label | //============ {Ans1} ============// | If 'Yes' is selected
Sheena | I'm happy to hear that. |
| --> Change the icon to {smile} |
$sync | jump to label |
| Jump to {Confluence} |
#label | //============ {Ans2} ============// | If 'No' is selected
Sheena | Don't say that! |
SFText一つのSFText内で、ラベル名の重複は許されないことに注意してください。
#defineマクロスコープ
#define
マクロスコープは、パラメータとして与える定数を定義するためのマクロスコープです。パラメータとして、シンボルと置き換え先の値を渡します。
#define | {symbol} {value} |
SFText#define
を宣言すると、SFTextがUnityにインポートされるとき、指定されたシンボルが同じく指定した別の値で置き換えられます。
$serial | change character image async |
| Change {X}'s image to {Normal} |
X | Hello, I'm Sheena. |
#define | {X} {Sheena}. |
$serial | change character image async |
| Change {X}'s image to {Smile} |
X | I'm a ScenarioFlow instructor. |
| Nice to meet you! |
// | ---------------------------------- | 以下のように置き換わる
$serial | change character image async |
| Change {X}'s image to {Normal} |
X | Hello, I'm Sheena. |
$serial | change character image async |
| Change {Sheena}'s image to {Smile} |
Sheena | I'm a ScenarioFlow instructor. |
| Nice to meet you! |
SFText#define
マクロスコープは、それを宣言した次の行から有効です。#define
は上書き可能であり、同じシンボルに対して複数の#define
が宣言されていた場合、シンボルが書かれた行より上の行で、最も新しい#define
の値が使用されます。
また、#define
がシンボルを置き換える対象は、以下のパラメータのみです。
- コマンドスコープのパラメータ(トークンコードを除く)
- セリフスコープの話者名
- 拡張セリフスコープの追加パラメータ
マクロスコープの有効範囲
1つのマクロスコープは1つのSFTextスクリプト全体に影響を及ぼしますが、他のSFTextスクリプトには影響を与えません。
例えば、#define
を宣言したとき、それが宣言されたSFTextとは別のSFText内にあるシンボルが置き換えられるようなことはありません。あくまで、#define
が宣言されたSFText内にのみ効力を発揮します。
また、#label
についてラベル名の重複は許されないと説明しましたが、それは1つのSFText内での場合で、2つの異なるSFText間でなら同名のラベルがあっても問題ありません。加えて別の観点で考えると、あるSFTextから別のSFTextのラベルを直接参照してシナリオ分岐を行うことはできないということです。
コメントスコープ
コメントスコープは、実際の会話シーンに影響しない、コメント文を記述するためのスコープです。以下の規則に従って記述します。
- スコープ宣言部を
//
で開始することで、コメントスコープを開始する - スコープ内では、コンテンツ記述部とコメント記述部の両方にコメントを記述できる
// (any text) | comment | commnet
SFTextスクリプトに書いた内容の意図を別の人あるいは後の自分自身に伝えるため、または一時的に不要なスコープをコメントアウトするために使用します。
#command | {write dialogue async} |
#token | {$standard} |
// Sheena | Hello, I'm Sheena. |
Sheena | I'm a ScenarioFlow instructor. |
| Nice to meet you! |
SFTextSFTextの編集
SFTextは既に述べられた通り、Visual Studio Code (VSCode) とその拡張機能を使用して快適に編集を行うことができます。ここまではSFTextの文法について学習してきましたが、ここからは実際にSFTextを書き上げる環境、そして効率の良い書き方に焦点を当てます。VSCodeの拡張機能でどのような機能が提供されているのか、どのようにそれらを使うのかを学んでいきましょう。
シンタックスハイライト
VSCodeの拡張機能を導入すると、SFTextに対してシンタックスハイライトが有効になります。
上の画像では、カラーテーマとしてAyu Dark Borderedが選択されています。VSCodeのカラーテーマは好きなものを使用できますが、SFTextのシンタックスハイライトはカラーテーマ「Ayu」向けに最適化されているので、SFTextの編集時はAyuのテーマのどれかを選択することをお勧めします。
フォーマッター
拡張機能では、テキストを整列させるフォーマッターが提供されています。
フォーマッターは、コマンドパレットからFormat Document
を選択するか、Shift+Alt+F
(Windowsの場合)で呼び出すことができます。ただし、SFTextの編集においてフォーマッターのみを直接的に呼び出すことはなく、その他の頻繁に使う機能を呼び出すときに、自動的に呼び出されるようになっています(VSCodeの機能で、ファイルのセーブ時にフォーマッターを呼び出すようにもできます)。
オートコンプリートとショートカットキーを使用した素早い編集
拡張機能が提供するオートコンプリート(入力補完)とショートカットキーを駆使することによって、SFTextを効率的に、素早く編集することができます。ここでは、その機能を使用するために必要な事前準備と、具体的な使い方について学びます。
コマンド情報の登録
オートコンプリートとショートカットキーをフルに活用するためには、C#側で定義しているコマンドの情報を拡張機能に渡す必要があります。そのために必要な手順は、次の通りです。
- コマンドとしてエクスポートするC#メソッドに、必要な属性を付加する
- SFText Snippets Builderによって、JSONファイルを生成する
- VSCode側で、JSONファイルを
Select JSON Path
コマンドにより選択し、Load JSON File
コマンドでロードする
順番に、これらの手順を見ていきましょう。
1. 属性の付加
まず、コマンドとしてエクスポートするC#メソッドに、いくつかの属性を付加します。例として、以下にshow two selections async
コマンドに対応するShowTwoSelectionsAsync
メソッド、そしてwrite dialogue and image async
コマンドに対応するWriteDialogueAndChangeImageAsync
メソッドを示します。
using ScenarioFlow;
using ScenarioFlow.Scripts.SFText;
[CommandMethod("show two selections async")]
[Category("Branch")]
[Description("Show two selections two the player.")]
[Description("Move on to one of specified labels that correspondes to the answer.")]
[Snippet("{${1:selection1}}")]
[Snippet("--- Jump to {${2:label1}}")]
[Snippet("{${3:selection2}}")]
[Snippet("--- Jump to {${4:label2}}")]
public async UniTask ShowTwoSelectionsAsync(string selection1, string label1, string selection2, string label2, CancellationToken cancellationToken)
{
// 省略
}
[CommandMethod("write dialogue and image async")]
[Category("Dialogue")]
[Description("Show a dialogue on the screren.")]
[Description("Also, change the character icon.")]
[DialogueSnippet("Change the icon to {${1:image}}")]
[Snippet("{${1:speaker}}")]
[Snippet("{${2:dialogue}}")]
[Snippet("Change the icon to {${3:image}}")]
public async UniTask WriteDialogueAndChangeImageAsync(string speaker, string dialogue, Sprite sprite, CancellationToken cancellationToken)
{
// 省略
}
C#各属性の概要を、以下に示します。CommandMethod
属性以外は、ScenarioFlow.Scripts.SFText
名前空間で定義されています。
属性 | 概要 |
---|---|
CommandMethod | コマンド名を指定する |
Category | コマンドのカテゴリを指定する |
Description | コマンドの説明を記述する。複数個に分けて記述できる。 |
Snippet | コマンドスコープで挿入されるスニペットを記述する。複数個付与でき、その場合スニペットは複数行に分かれる。 |
DialogueSnippet | 拡張セリフスコープで挿入されるスニペットを記述する。複数個付与でき、その場合スニペットは複数行に分かれる |
CommandMethod
以外の属性はオプションですが、すべて、VSCodeでの入力支援のために使用されます。特に、編集の効率を上げるため、少なくともSnippet
とDialogueSnippet
は付加しておいた方が良いでしょう。DialogueSnippet
は、拡張セリフスコープで使用されるコマンドにのみ付加することに注意してください。
Snippet
属性とDialogueSnippet
属性には、SFTextを見返したときに、そのコマンドあるいはセリフスコープで何が起きるのかを簡単に想像できるようなテキストを渡します。そして、そのテキストには、コマンドに渡すパラメータを{${n:name}}
の形式で埋め込みます。n
はパラメータ番号を、name
にはパラメータ名を書きます。すると、コマンドや拡張セリフスコープのパラメータをスニペット(テキストのテンプレート)により効率的に入力することができ、それらの振る舞いも分かりやすいものになります。
トークンコードはパラメータとして埋め込まないこと、DialogueSnippet
属性については、話者名とセリフ内容に対応するパラメータを抜くことに注意してください。また、Snippet
属性とDialogueSnippet
属性は共存可能です(セリフスコープはコマンドスコープの省略表記なので、セリフスコープで使用するコマンドは普通のコマンドスコープでも呼び出せる)。
2. JSONファイルの生成
Unityエディタの上部メニューのWindow/ScenarioFlow/SFTextSnippetsBuilder
から、SFText Snippets Builderを開きます。そして、以下の手順でJSONファイルを生成します。
- Projectウィンドウで右クリックし、
Create/ScenarioFlow/SFText Snippets
から、空のJSONファイルを作成する - SFText Snippets Builderの
Edit
ボタンを押し、Add JSON Text
ボタンを押してスロットを増やしたら、そこへ作成したJSONファイルをドラッグ&ドロップで紐づけ、Save
ボタンで保存する Update JSON Files
ボタンを押して、登録したJSONファイルにコマンド情報を書き込む
ちなみに、JSONファイルにはCommand Listにおいてチェックボックスが有効になっているコマンドのみが出力されます。また、Copy JSON to Clipboard
ボタンにより、手動でJSONテキストをコピーすることもできます。
3. JSONファイルの登録
生成したJSONファイルを、次の手順でVSCodeへ登録します。
- コマンドパレットから
Select JSON Path
を呼び出し、生成したJSONファイルを選択 - コマンドパレットから
Load JSON File
を呼び出し、選択したJSONファイルを読み込む
これでコマンドの情報がVSCodeに登録され、拡張機能による入力支援が完全に有効になります。後にC#側で新たなコマンドを定義したり、属性に変更を加えたりした場合は、JSONファイルのパスが変わらない限りは、(1)SFText Snippets BuilderでJSONファイルを更新、(2)VSCodeのLoad JSON File
で更新されたJSONファイルを読み込み、の2ステップでその変更を反映させることができます。ちなみに、登録したJSONファイルの内容を、更新することなく単に削除したい場合は、VSCodeでClear JSON Data
コマンドを呼び出します。
SFText Command List
上部メニューからWindow/ScenarioFlow/SFText Command List
を選択してSFText Command Listを開き、定義されているコマンドとデコーダの情報を、一覧で確認することができます。
二番目の画像が示す通り、実は、コマンドに付加できる属性の中でCategory
属性とDescription
属性は、デコーダにも付与することができます。
using ScenarioFlow;
using ScenarioFlow.Scripts.SFText;
[DecoderMethod]
[Category("Resource")]
[Description("Decoder for 'Sprite'.")]
[Description("Sprites need to be registered so that they will be available.")]
public Sprite GetSprite(string name)
{
if (spriteDictionary.TryGetValue(name, out var sprite))
{
return sprite;
}
else
{
throw new ArgumentException($"Sprite '{name}' does not exist.");
}
}
C#オートコンプリート
以下の要素に対して、サジェストによるオートコンプリートを使用できます。特に、コマンドのオートコンプリートには、JSONファイルで登録したコマンド情報が反映されていることに注意してください。
- マクロスコープのマクロ名
- コマンドスコープのトークンコード
- コマンドスコープのコマンド名
ショートカットキー
オートコンプリートに加えて、以下の3つのコマンドを使用することで、効率的にSFTextを記述することができます。コマンドはコマンドパレットから呼び出すこともできますが、普通はショートカットキーにより素早く呼び出します。また、すべてのコマンドはフォーマッターを呼び出し、スクリプトを整形することも覚えておいてください。
コマンド | ショートカットキー(Windows) | 役割 |
---|---|---|
Move Cursor | Shift+Enter | カーソルをスコープ宣言部、コンテンツ記述部、コメント記述部の最後尾へ、順番に移動させる |
Insert Arguments | Alt+Enter | カーソルの置かれているスコープに必要なパラメータのスニペットを挿入する |
Insert Line Below | Ctrl+Enter | カーソルのある行の下に新しい行を挿入する |
各スコープの記述例
各スコープについて、オートコンプリートとショートカットキーを駆使した効率的な記述方法を見ていきます。
マクロスコープ
マクロスコープの記述は最も簡単です。マクロ名をオートコンプリートで入力して、Alt+Enter
でスニペットを挿入してパラメータを埋めるだけです。
コマンドスコープ
- トークンコードを入力し、
Shift+Enter
- コマンド名を入力し、
Alt+Enter
- スニペットでパラメータを入力し、
Ctrl+Enter
スニペットのパラメータ入力では、Tabキーによりカーソルを次のパラメータ位置へ移動させられます。
セリフスコープ
- 話者名を入力し、
Shift+Enter
- セリフ内容を入力して
Ctrl+Enter
- セリフがまだあるなら何も書かずに
Shift+Enter
し、手順2へ。ないなら次のスコープを開始
追加パラメータを与える拡張セリフスコープの場合は、セリフを書き終わったらそのスコープ上でAlt+Enter
を押し、スニペットを挿入します。
拡張セリフスコープ上でAlt+Enter
を押したときに挿入されるスニペットは、その拡張セリフスコープの上で宣言されている中で、最も新しい#xcommand
マクロスコープで指定されているコマンドに付加されたDialogueCommand
属性の値に対応しています。また、ターゲットとなる拡張セリフスコープの上側で#xcommand
マクロスコープが一つも宣言されていない場合はスニペットが挿入できないので注意してください。
Sheena | Good morning! | ここではスニペットを挿入できない
#xcommand | {Command A} |
Sheena | Hello! | ここではCommand Aのスニペットが挿入される
#xcommand | {Command B} |
Sheena | Hi! | ここではCommand Bのスニペットが挿入される
SFText拡張機能の設定項目
半角文字の登録
拡張機能のフォーマッターは、SFText内の縦線の位置がそろうようにテキストを整形してくれますが、その処理の中で、フォーマッターは各文字が半角文字か全角文字かを判定しています。一般的な半角アルファベットや半角記号は正しく半角文字であると判定されるのですが、一部の特殊な半角文字は正しく半角文字であると認識されません。例えば、「…」は半角文字ですが、初期状態ではフォーマッターに全角文字であると判定され、テキストの整列が正しく行われません。
このように、使用しようとした半角文字が正しく半角文字であると認識されなかったとき、設定を変更することでその問題を解決することができます。
VSCodeの設定を開き、検索バーに「sftext」と入力します。するとHalf Width Character Listという項目が現れるので、そこに半角文字と認識してほしい文字のセットを、正規表現で入力します。デフォルトでは\x01-\x7E\uFF65-\uFF9F
が入力されており、これで一般的な半角文字はカバーされています。初期値は広範囲の文字をカバーするためにUTF-8の文字コードを使用していますが、実際にこの設定を変更するときは、半角文字として認識させたい新たな文字をそのまま付け足せばよいです。
今回の例では、「…」を設定値に付け足します。
すると、「…」を含むテキストが正しく整形されるようになります。
マクロスコープに対するスニペットのカスタマイズ
コマンドスコープのスニペットはC#側で属性を付加することによって設定できましたが、マクロスコープのスニペットは、VSCodeの設定で変更できます。設定を開いて検索バーに”sftext”と入力すると、Half Width Character Listの下に、各マクロスコープに対するスニペットの設定項目が並んでいるのが確認できます。
これらの項目に、Snippet
属性と同様の形式でスニペットとして挿入されるテキストを入力することで、好きなスニペットを各マクロスコープに対して登録できます。
まとめ
今回の記事では、SFTextの文法、そしてVSCodeの拡張機能を使用した効率的な編集について学習しました。
SFTextでは、各行は縦線「|」により、スコープ宣言部、コンテンツ記述部、コメント記述部の3つの領域に分割されます。
領域 | 何を記述するか |
---|---|
スコープ宣言部 | スコープを開始するためのシンボルを記述する |
コンテンツ記述部 | パラメータなど、スコープの内容を記述する |
コメント記述部 | コメントを記述する(会話シーンに影響しない) |
スコープ宣言部 | コンテンツ記述部 | コメント記述部
SFTextSFTextは複数の「スコープ」から構成され、スコープには以下の4種類があります。
スコープ | 役割 |
---|---|
コマンドスコープ | コマンド呼び出しを引き起こす |
セリフスコープ | セリフを表示するためのコマンド呼び出しを引き起こす |
マクロスコープ | コマンド・セリフスコープの補助をする |
コメントスコープ | コメントを記述する(会話シーンに影響しない) |
コマンドスコープとセリフスコープがコマンド呼び出しを引き起こすので、SFTextでは会話シーンを記述するために、適切な順でコマンドスコープとセリフスコープを並べ、マクロスコープでそれらの補助をすることになります。サンプルプロジェクトの会話システムで上記のStory.sftxtを実行すると、以下のような会話シーンが再生されます。
SFTextの編集時には、VSCodeの拡張機能が提供するオートコンプリート、ショートカットキーを駆使しして効率的にスクリプトを記述できます。重要なショートカットキーは以下の三つです。
コマンド | ショートカットキー(Windows) | 役割 |
---|---|---|
Move Cursor | Shift+Enter | カーソルをスコープ宣言部、コンテンツ記述部、コメント記述部の最後尾へ、順番に移動させる |
Insert Arguments | Alt+Enter | カーソルの置かれているスコープに必要なパラメータのスニペットを挿入する |
Insert Line Below | Ctrl+Enter | カーソルのある行の下に新しい行を挿入する |
これらを使用して、例えばコマンドスコープは次のように、素早く記述できます。
なお、オートコンプリートとショートカットキーをフルに活用するためには、C#側でコマンドとしてエクスポートされるメソッドに対し、適切に属性を与えなければならないことに注意してください。そして、それらをもとに生成したJSONファイルをVSCodeへ登録する必要があります。
会話シーンを効率的に記述するため、まずはSFTextの文法を覚え、VSCodeにおける操作に慣れることから始めましょう。今回扱ったサンプルプロジェクトを使用して、SFTextを書く練習をしてみてください。
コメント