【ScenarioFlow】トークンコードの選び方

ScenarioFlow
ツールのバージョン
  • Unity: 2022.3.35f1
  • UniTask: 2.5.4
  • ScenarioFlow: 1.1.0
  • SFText Extension Pack: 1.1.0
    • Syntax: v1.1.0
    • Formatter: v1.0.0
    • Utility: v1.0.0

はじめに

ScenarioFlowで会話シーンを再生するために使用されるコマンドには、処理が即座に完了する同期コマンドと、処理の完了に時間がかかる非同期コマンドがあります。同期コマンドと非同期コマンドの違いで重要なのは、非同期コマンドにはトークンコードと呼ばれるパラメータを渡すことができ、それによって動作の振る舞いを変更することができるということです。

ScenarioFlowにおいてトークンコードは、シナリオスクリプトの構造を単純にしつつ、その表現力を高めるために重要な役割を担っています。言い換えれば、ScenarioFlowで自由自在に会話シーンを記述するためには、トークンコードの性質を理解し、有効活用することが必須であるということです。

今回の記事では、トークンコードについて学習します。いくつか種類があるトークンコードについて、それぞれの性質と使い分けについて理解することを目的とします。

ここでは、SFTextで主に使用されるトークンコードを学びます。

SFTextはScenarioFlowで会話シーン記述のために使用されるスクリプト形式ですが、実は、SFTextで使用できるトークンコードと、実際の会話システムで使用できるトークンコードは一致しません。これは、実際に存在するトークンコードのすべてを使い分けずに済むよう、SFTextが独自のトークンコードを用意しているためです。つまり、会話システムで実際に使われるトークンコードのうちいくつかは、SFTextでは使い分ける必要なく、同一のトークンコードとして記述できます。スクリプトに記述されたSFText独自のトークンコードは、Unityへインポートされるときに、実際の会話システムが理解できる適切なトークンコードに置き換えられます。

会話システムで実際に使用されるトークンコードについては、この記事の最後で触れます。まずは、SFTextで使用される実用的なトークンコードについて学びましょう。

サンプルプロジェクトのインストール

以下のhow-to-choose-tokencode.unitypackageをUnityのプロジェクトにインポートし、今回の学習に必要なプログラムとオブジェクトの準備をしてください。

サンプルプロジェクトに含まれるクラスとコマンドの中で、重要なものを以下に示します。他のクラスとコマンドについては、記事「SFTextの書き方」を参照してください。

クラス役割
ScenarioManager会話システムを構成し、会話シーンを再生するクラス
ButtonNotifierNextボタンを押して会話シーンを進め、Cancelボタンでコマンドをキャンセルする機能を実装する
SkipActivatorSkipボタンによるスキップモードの切り替えを有効にする
ShapeAnimator画面上の図形を動かすコマンドを定義する
ScenarioTaskConsumer「一般のトークンコード」を扱うためのコマンドを定義する
サンプルプロジェクトに含まれるクラスとそれぞれの役割
コマンド実行される演出実装クラス
move all shapes to left画面上の全図形を左に配置する(位置のリセット)ShapeAnimator
move shape to right async画面上の指定した図形を右に動かすShapeAnimator
accept task asyncシナリオタスクを待機するScenarioTaskConsumer
cancel task asyncシナリオタスクをキャンセルするScenarioTaskConsumer
会話システムに含まれるコマンドとその演出

ファイルをインポートしたら、how-to-choose-tokencode シーンを開くとサンプルシーンを実行できます。このサンプルプロジェクトでは、HierarchyウィンドウのScenarioManager オブジェクトのScenario Script プロパティに設定されているシナリオスクリプトが実行されていることになっています。始めに、Story.sftxtScenario Script プロパティに設定されていることを確認し、サンプルシーンを実行してみてください。

サンプルシーンの実行

このサンプルプロジェクトではNextボタンとCancelボタンが分かれており、前者で会話シーンを進め、後者で実行中の演出をキャンセルします。また、「スキップモード」のオンオフを切り替えるSkipボタンも配置されています。

画面上には三つの図形、円、三角形、四角形が配置されており、サンプルシーンではそれらの図形に対し円、三角形、四角形の順で繰り返し「アニメーションコマンド」が呼び出されます。そして、コマンド呼び出しのたびに、異なるトークンコードが与えられます。トークンコードによって図形がどのように移動するか、また図形の移動中、移動後にNextボタン、Cancelボタン、Skipボタンがどのような振る舞いをするのかを確認することで、各トークンコードの性質を理解することができるでしょう。

スキップモード

トークンコードの性質を理解し、適切に使い分けができるようになるためには、前提として「スキップモード」について知っている必要があります。このスキップモードについては別の記事で再び学習しますが、ここではトークンコードの性質を理解するため、最低限の説明にとどめます。

スキップモードは、プレイヤーが会話シーンにおいて物語を読み飛ばすことを可能にする機能です。サンプルプロジェクトではSkipActivator クラスでこの機能が実装されており、スキップボタンを押すことでスキップモードを有効にすることができます。実際にスキップモードを有効にしてみると、セリフがスキップ、つまり高速に次々表示され、ある地点でスキップが止まったように見えるのが確認できます。

スキップモードを有効にするとたいていの演出をスキップできるが、一部演出はできない

スキップモードが有効になると、基本的に非同期コマンドがスキップされるようになります。「コマンドがスキップされる」というのは、あるコマンドが実行されてから即座にキャンセルされ、その後すぐに次のコマンドが実行されることを意味します。この振る舞いに、INextNotifier インターフェースやICancellationNotifier インターフェースの実装は関与しません。

重要なのは、このスキップは特定のトークンコードが渡された非同期コマンドには適用されないということです。サンプルプロジェクトではスキップモードが有効になったとき、スキップされるコマンドとスキップされないコマンドがありますが、この違いはそれらのコマンドに指定されているトークンコードの違いに由来します。上の実行例では、スキップモードが有効になっているにもかかわらず画面上の円がゆっくりと移動していますが、これはそのアニメーションを引き起こしているコマンドに「スキップ禁止」のトークンコードが指定されていることを意味します。

トークンコードの分類

SFTextで主に使用するトークンコードは、以下の8種類です。

  1. standard
  2. forced
  3. promised
  4. f-standard
  5. f-forced
  6. f-promised
  7. serial
  8. parallel

ここでは、これらのトークンコードを「キャンセル許可レベル」、「後続コマンドの開始タイミング」、「直列接続・並列接続」の三つの観点から分類していきます。

キャンセル許可レベル

トークンコードは非同期コマンドに対するパラメータとして渡されますが、非同期コマンドは、その処理の実行途中でキャンセルすることができます。しかし、実際の会話シーンでは、キャンセルしてほしくない、あるいはキャンセルしてはいけない非同期コマンドもあります。例えば、あるセリフが演出上重要であるためプレイヤーに読み飛ばしてほしくないときや、選択肢の表示で、何かしらの選択肢が選択されないとシナリオの分岐先を決定できない場合などです。

トークンコードのstandard, forced, promisedを使い分けることで、その非同期コマンドがどのレベルのキャンセルを許可するのかを指定できます。以下の表に、この指定に使用されるトークンコードとその性質、選択のガイドラインを示します。

トークンコードキャンセル命令スキップ命令選択のガイドライン
standard, f-standard許可許可キャンセルされてもいいコマンドに
forced, f-forced禁止許可キャンセルされるべきでないコマンドに
promised, f-promised禁止禁止キャンセルされてはいけないコマンドに
キャンセル許可レベルによるトークンコードの分類と選択のガイドライン

キャンセル命令は、CancellationNotifier(ICancellationNotifier の実装)によって発行される命令です。 ICancellationNotifier を実装するクラスで宣言されているNotifyCancellationAsync メソッドが完了したとき、「キャンセル命令」が発行され、その結果非同期コマンドがキャンセルされます。

一方、スキップ命令は、スキップモードにより発行される命令です。スキップモードが有効な間、非同期コマンドが実行されるたびに「スキップ命令」が発行され、非同期コマンドがスキップ、つまりキャンセルされます。

上の表に示される通り、(f-)standardはキャンセル命令もスキップ命令も受け付け、(f-)forcedはキャンセル命令は受け付けないがスキップ命令は受け付け、(f-)promisedはキャンセル命令もスキップ命令も受け付けません。以下にstandard, forced, promisedの動作例を示します。

‘standard’ の動作例。キャンセルもスキップも有効
standardの動作確認
$standard   | move shape to right async  | 
            | Move {Circle} to right     | 
$standard   | move shape to right async  | 
            | Move {Triangle} to right   | 
$standard   | move shape to right async  | 
            | Move {Square} to right     | 
SFText
‘forced’ の動作例。キャンセルはできないが、スキップはできる
forcedの動作確認
$forced     | move shape to right async  | 
            | Move {Circle} to right     | 
$forced     | move shape to right async  | 
            | Move {Triangle} to right   | 
$forced     | move shape to right async  | 
            | Move {Square} to right     | 
SFText
‘promised’ の動作例。キャンセルもスキップもできない
promisedの動作確認
$promised   | move shape to right async  | 
            | Move {Circle} to right     | 
$promised   | move shape to right async  | 
            | Move {Triangle} to right   | 
$promised   | move shape to right async  | 
            | Move {Square} to right     | 
SFText

状況に応じた適切な選択のポイントは、まず「システム上キャンセルはOKか」、次に「演出上そのコマンドがどのくらい重要なのか」です。

例えば、プレイヤーに選択肢を与えるコマンドは、いずれかの選択肢を選択してもらわないとシナリオの分岐先がわからないので、システム上キャンセルはしていけません。そのため、そのようなコマンドにはキャンセル命令の発行もスキップ命令の発行も禁止する(f-)promisedを指定することで、その処理が絶対にキャンセルされないようにすることができます。

一方で、システム上はキャンセルが許される場合、そのコマンドの演出上の重要度を考えます。例えばセリフを表示するコマンドについて、基本的には完全にキャンセルを許可する(f-)standardを指定します。しかし、ストーリー上重要なのでそれを読み飛ばしてほしくはないが、どうしてもプレイヤーがそうしたい場合にはそれを許可したいのであれば(f-)forcedを、絶対に全文を丁寧に読んでほしいのであれば(f-)promisedを指定します。

(f-)forcedと(f-)promisedの違いは特に重要で、前者は「キャンセルされるべきでない」、後者は「キャンセルされてはいけない」を表すと理解しておくと良いでしょう。

後続コマンド開始タイミング

ある非同期コマンドの処理が完了した際、次のコマンドが実行されるのは、通常INextNotifier インターフェースの実装が定義するNotifyNextAsync メソッドの処理が完了した後です。例えば、画面がタップされたときにNotifyNextAsync メソッドが完了するようにしておけば、あるセリフが非同期コマンドによって表示された後、プレイヤーが画面をタップしたときに次の非同期コマンドが実行され、次のセリフが表示され始めるといった挙動が実現できます。

これを言い換えれば、ある非同期コマンドの処理が完了した後、基本的に次のコマンドの開始はNextNotifier(INextNotifier の実装)によって「進行命令」が発行されるまで遅延されるということです。しかし、特定のトークンコードを非同期コマンドに渡すことによって、その処理が完了した後、進行命令を無視して即座に次のコマンドを開始させることができます。以下に、この観点でのトークンコードの分類とその性質、選択のガイドラインを示します。

トークンコード進行命令選択のガイドライン
standard, forced, promised待機セリフの表示に
f-standard, f-forced, f-promised無視アニメーションや選択肢の表示に
後続コマンド開始タイミングの観点でのトークンコードの分類と選択のガイドライン

standard, forced, promisedの頭にf-を付けると、その非同期コマンドが完了した後、進行命令を無視して即座に次のコマンドが開始されます。逆にf-がない場合、非同期コマンドの完了後、通常通り進行命令を待機して、それが発行されてから次のコマンドが開始されます。ちなみに、f- は”fluent”の頭文字です。

以下に、standardとf-standardの動作例を示します。コマンド完了後、Nextボタンを押さずとも次のコマンドが開始されていることに注目してください。

‘standard’ の動作例。コマンド完了後、Nextボタンが押されるまで次のコマンドは開始されない
standardの動作確認
$standard   | move shape to right async  | 
            | Move {Circle} to right     | 
$standard   | move shape to right async  | 
            | Move {Triangle} to right   | 
$standard   | move shape to right async  | 
            | Move {Square} to right     | 
SFText
‘f-fluent’ の動作例。コマンド完了後、Nextボタンを押さずとも次のコマンドが即座に開始される
f-standardの動作確認
$f-standard   | move shape to right async  | 
              | Move {Circle} to right     | 
$f-standard   | move shape to right async  | 
              | Move {Triangle} to right   | 
$f-standard   | move shape to right async  | 
              | Move {Square} to right     | 
SFText

fluentでないトークンコード (standard, forced, promised)は、主にセリフの表示をするコマンドに対して指定します。あるセリフが表示された後、画面のタップなどのプレイヤーのアクションを待ってから次のセリフを表示するという、自然な振る舞いを実現することができます。standard, forced, promisedのどれを使うかは、前述の通り、そのセリフの重要度によります。

fluentなトークンコード(f-standard, f-forced, f-promised)は、アニメーションや、選択肢の表示を行うコマンドに使用します。そのようなコマンドにfluentでないトークンコードを指定すると、あるアニメーションが終わった後、もしくは選択肢をプレイヤーが選択した後に、プレイヤーが何らかのアクションを起こさないと次のセリフに移行しないという少々不自然な振る舞いとなってしまいます。fluentなトークンコードのうちどれを使うかは、コマンドによって引き起こされる演出の重要度と、システム上キャンセルが許されるかどうかによって決めます。

直列接続・並列接続

トークンコードserialもしくはparallelを指定することで、その非同期コマンドを次の非同期コマンドと結合させ、一つのコマンドとして実行することができます。次の表に、これらのトークンコードの性質をまとめます。

トークンコード接続方式進行命令キャンセル命令スキップ命令
serial直列無視後続と同じ後続と同じ
parallel並列後続と同じ後続と同じ後続と同じ
コマンドを結合するトークンコードの性質

serialは直列接続を意味し、接続されたコマンドが順番に実行されます。fluentなトークンコードを指定したときと同様、一つのコマンドが完了した後は即座に次のコマンドが開始されますが、fluentなコマンドを書き連ねた場合と異なり、接続されたコマンドのうちどれか一つがキャンセルされると、他のコマンドもすべてキャンセルされます。

‘serial’の動作例(キャンセルなし)。キャンセルなしの場合は’fluent’と同様の振る舞いをする
‘serial’の動作例(キャンセルあり)。接続されたコマンドの一つがキャンセルされると、他のコマンドもキャンセルされる
serialの動作確認
$serial     | move shape to right async  | 
            | Move {Circle} to right     | 
$serial     | move shape to right async  | 
            | Move {Triangle} to right   | 
$standard   | move shape to right async  | 
            | Move {Square} to right     | 
SFText

parallelは並列接続を意味し、接続されたコマンドは同時に実行されます。コマンドが同時に実行されるので、コマンドがキャンセルされるときはすべてのコマンドが同時にキャンセルされます。

‘parallel’の動作例(キャンセルなし)。接続されたコマンドが同時に実行される
‘parallel’の動作例(キャンセルあり)。すべてのコマンドが同時にキャンセルされる。
parallelの動作確認
$parallel   | move shape to right async  | 
            | Move {Circle} to right     | 
$parallel   | move shape to right async  | 
            | Move {Triangle} to right   | 
$standard   | move shape to right async  | 
            | Move {Square} to right     | 
SFText

注意として、serialもしくはparallelを指定した非同期コマンドのキャンセル許可レベルは、それが接続されているコマンドのものと同じになります。例えばserialもしくはparallelを指定した非同期コマンドが(f-)standardを指定したコマンドに接続されていればキャンセル命令もスキップ命令も受け入れられますが、(f-)promisedを指定したコマンドに接続されていればそのどちらによってもキャンセルはされません。

これらのトークンコード、serialとparallelを使う場面としてよくあるのは、キャラクターに対する小さなアニメーションをつなげて一つのアニメーションにするようなときです。キャラクターに複雑な動きをさせたいときに、それを可能にする専用のコマンドを用意しているとコマンド数がどんどん増えていきますが、単純なアニメーションを引き起こす小さなコマンドをいくつか用意してそれらを組み合わせるようにすれば、ある程度のコマンド数で複雑なアニメーションを作ることができます。

トークンコードまとめ

トークンコードの性質を以下の表にまとめます。

トークンコード進行命令キャンセル命令スキップ命令
standard待機許可許可
forced待機禁止許可
promised待機禁止禁止
f-standard無視許可許可
f-forced無視禁止許可
f-promised無視禁止禁止
serial無視後続と同じ後続と同じ
parallel後続と同じ後続と同じ後続と同じ

進行命令はINextNotifier インターフェースの実装から発行される、あるコマンドが完了した後に次のコマンドを開始するために命令で、キャンセル命令はICancellationNotifier の実装から発行される、あるコマンドの実行中に、そのコマンドのキャンセルを引き起こす命令です。スキップ命令は、スキップモードが有効になっている間に発行され続ける、コマンドの開始とキャンセルを繰り返す命令です。

まず、基本のトークンコードとしてstandard、forced、promisedがあり、これらが指定されたコマンドが完了した後は、進行命令が発行されるのを待機してから次のコマンドが実行されます。そして、キャンセル命令とスキップ命令が許可されるかどうかは指定されているトークンコードによります。

次に、上記のトークンコードの頭にf-を付けたfluentなトークンコード、f-standard、f-forced、f-promisedがあり、これらが指定されたコマンドが完了した後は、進行命令を待たず、即座に次のコマンドが開始されます。そして、キャンセル命令とスキップ命令が許可されるかどうかはトークンコードによります。

最後に、複数のコマンドを接続するためのトークンコード、serialとparallelがあり、これらのトークンコードを指定したコマンドは後続の非同期コマンドと接続されます。serialの場合、接続されたコマンドは順番に実行され、fluentなトークンコードを指定したときのようにあるコマンドの完了後は次のコマンドが即座に開始されますが、一つのコマンドがキャンセルされると他のコマンドも一斉にキャンセルされるという点でfluentなトークンコードと異なります。parallelの場合、接続されたコマンドは同時に実行され、キャンセルされるときはすべてが同時にキャンセルされます。これらのトークンコードが指定されたコマンドのキャンセル許可レベルは、接続先のコマンドのそれと一致します。

トークンコードの選び方としては、対象とするコマンドの役割に注目します。例えば、セリフを表示するコマンドの場合、セリフが表示された後、画面のクリックなどのプレイヤーアクションを待ってから次のセリフを表示させたいのでfluentでないトークンコードを指定します。キャンセル許可レベルは、そのセリフの重要度によって決めます。一方で選択肢を表示させるコマンドの場合、システム上キャンセルはできないのでpromisedなトークンコードを指定します。fluentなものでもfluentでないものでも動作上は問題ありませんが、選択肢を選択後は即座に次の演出に移行した方が自然な演出になるのでfluentな方、f-promisedを選択します。

その他の機能

ここまでに、特にSFTextにおける、トークンコードの主な用法について学習しました。このセクションでは、トークンコードについてその他の用法を学習します。ここで取り扱う機能はほとんど使用されないかつ、使用も推奨されないため、読み飛ばしても構いません。

12種類のトークンコード

すでに学習した8種類のトークンコードは、正確にはSFTextにおいて使用できるトークンコードです。実際にScenarioFlowのシステム内で取り扱われるトークンコードは、以下の12種類があります。

ベース標準FluentSerialParallel
standardstandardf-standards-standardp-standard
forcedforcedf-forceds-forcedp-forced
promisedpromisedf-promiseds-promisedp-promised

接頭辞のない標準形式と、接頭辞f- のついたFluent形式は、SFTextにおいて使われるそれらと同じです。接頭辞s-p- がそれぞれ付いたSerial形式とParallelについては、SFTextで使用されるserial トークンコードとparallel トークンコードとは異なり、接続先のコマンドに関係なくキャンセル許可レベルを指定できるという点のみ異なります。

重要な点は、Serial形式とParallel形式の使用において、それらを指定するコマンドのキャンセル許可レベルは、それぞれが接続されるコマンドのキャンセル許可レベルと同一のものにする場合がほとんどで、またそれが最も自然な演出につながるということです。そのために、SFTextでは単純化のためにトークンコードserialparallel でSerial形式とParallel形式のトークンコードが代替され、UnityへのSFTextのインポート時にserialparallel が、それらが指定されたコマンドの接続先と同じキャンセル許可レベルを持つSerial形式またはParallel形式のトークンコードで置き換えられるようになっています。実際に、SFTextのInspectorウィンドウを見ると、そのような変換が行われていることがわかります。

SFTextのInspectorウィンドウ。”SFText”タブで見られるのが元々のテキストで、”Scenario Script”タブでみられるのが変換後のデータ。例えば、4行目の最後の要素が”p-standard”となっているが、これま元々”parallel”だった

特別な理由がない限りは、コマンドを直列または並列接続する場合、s-standardやp-forcedなどで明示的にキャンセル許可レベルを指定することはせず、単にserialparallelと書くのが良いでしょう。

一般のトークンコード

SFTextでは主に8種類のトークンコードを使用し、システム内では12種類のトークンコードが取り扱われていることを学習しました。実は、それ以外のトークンコードも渡すことができます。12種類のトークンコードを「特別なトークンコード」、それ以外のトークンコードを「一般のトークンコード」と呼びます。

一般のトークンコードを指定した非同期コマンドはScenarioTaskExecutor クラスの中に「シナリオタスク」として格納され、他の特別なトークンコードが指定された非同期コマンドと隔離されて実行されます。その非同期コマンドが開始した後は、parallel同様に即座に次のコマンドが開始されますが、後続の非同期コマンドとリンクされているわけではありません。

シナリオタスクは、ScenarioTaskExecutor クラスが実装するIScenarioTaskStorage のメンバメソッドであるAcceptAsync メソッドで待機することができ、Cancel メソッドでキャンセルすることができます。これらのメソッドを利用することで、一般のトークンコードを取り扱うためのコマンドを作成できます。例として、サンプルプロジェクトのScenarioTaskConsumer クラスを参照してください。

ScenarioTaskConsumer.cs
using Cysharp.Threading.Tasks;
using ScenarioFlow;
using ScenarioFlow.Scripts.SFText;
using ScenarioFlow.Tasks;
using System;
using System.Threading;

namespace HowToChooseTokenCode
{
	public class ScenarioTaskConsumer : IReflectable
    {
        private readonly IScenarioTaskStorage scenarioTaskStorage;

        public ScenarioTaskConsumer(IScenarioTaskStorage scenarioTaskStorage)
        {
            this.scenarioTaskStorage = scenarioTaskStorage ?? throw new ArgumentException(nameof(scenarioTaskStorage));
        }

        [CommandMethod("accept task async")]
        [Category("Task")]
        [Description("Await scenario tasks with the specified token code.")]
        [Snippet("Accept {${1:token code}}")]
        public async UniTask AcceptScenarioTasksAsync(string tokenCode, CancellationToken cancellationToken)
        {
            await scenarioTaskStorage.AcceptAsync(tokenCode, cancellationToken);
        }

        [CommandMethod("cancel task")]
        [Category("Task")]
        [Description("Cancel scenario tasks with the specified token code.")]
		[Snippet("Cancel {${1:token code}}")]
		public void CancelTask(string tokenCode)
        {
            scenarioTaskStorage.Cancel(tokenCode);
        }
    }
}
C#

accept task async コマンドは、指定された一般のトークンコードと結び付けられているシナリオタスクの完了を待機し、cancel task コマンドはキャンセルを引き起こします。これらのコマンドを使った、一般のトークンコードの動作例を確認しましょう。ここから紹介する動作例は、サンプルプロジェクト内のGeneralTokenCode.sftxt で確認できます。このSFTextを、ScenarioManagerオブジェクのScenario Script プロパティにセットしてください。

以下のスクリプトでは、すべての図形が同時に移動し、一見最初の二つにparallelを指定したときと同じように見えます。しかし、parallelが指定された二番目のコマンドとf-standardが指定された三番目のコマンドはリンクされているのに対し、”task1″トークンコードが指定された、一番最初のコマンドは他のどのコマンドともリンクしていません。このことは、アニメーションをキャンセルしてみると良くわかります。アニメーションが開始してからCancelボタンを押すと、parallelとf-standardが指定されたコマンドはキャンセルされますが、”task1″が指定されたコマンドはキャンセルされません。コマンドのキャンセル後はaccept task async でtask1のコマンドの完了が待機され、accept task async にはpromisedが指定されているのでキャンセルできません。

SFText
$task1      | move shape to right async  | 
            | Move {Circle} to right     | 
$parallel   | move shape to right async  | 
            | Move {Triangle} to right   | 
$f-standard | move shape to right async  | 
            | Move {Square} to right     | 
            |                            | 
$promised   | accept task async          | 
            | Accept {task1}             | 
SFText
Cancelボタンを押しても”task1″のコマンドはキャンセルされない

同じトークンコードを指定したシナリオタスクは、一括で完了を待機またはキャンセルします。以下のスクリプトでは、cancel task コマンドによって、”task2″を指定したシナリオタスクをすべてキャンセルしています。アニメーションが完了する前にセリフを読み飛ばすことで、キャンセルの挙動が確認できます。

SFText
$task2      | move shape to right async                                                | 
            | Move {Circle} to right                                                   | 
$task2      | move shape to right async                                                | 
            | Move {Triangle} to right                                                 | 
$task2      | move shape to right async                                                | 
            | Move {Square} to right                                                   | 
Sheena      | Click the cancel button and next button quickly to cancel the animation! | 
$sync       | cancel task                                                              | 
            | Cancel {task2}                                                           | 
SFText
共通のトークンコードを持つシナリオタスクが同時にキャンセルされる

一般のトークンコードにより、コマンド実行の自由度は上がりますが、以下の2つの理由からこの機能の使用は推奨されません。

  • 処理の流れが複雑になり、シナリオスクリプトから実際に再生される会話シーンを想像するのが難しくなること
  • 会話シーンにセーブ機能を実装する場合、この機能の乱用は容易に不具合を引き起こすこと

実用上は、一般のトークンコードを使用することなく、特別なトークンコードのみで十分柔軟に会話シーンを構成できます。

おわりに

今回の記事では、非同期コマンドにパラメータとして渡されるトークンコードについて学習しました。トークンコードは、1つの非同期コマンドを様々な方法で実行することを可能にする、柔軟に会話シーンを記述する上での強力な武器です。他方で、不適切なトークンコードの指定は不自然な演出を招いたり、システム上の不具合を招いたりします。そのため、各トークンコードの性質を理解し、状況に応じて適切なトークンコードを選択できるようにしましょう。

コメント