コンテンツにスキップ

カスタムコマンド ​

コマンドは、シーンで何が起こるかを制御する単一の操作を表します。たとえば、背景の変更、キャラクターの移動、別のシナリオスクリプトのロードなどです。シナリオスクリプト で定義されたパラメーター付きのコマンドシーケンスが、実質的にゲームフローを制御します。利用可能な組み込みコマンドは APIリファレンス で確認できます。コードでは、すべての組み込みスクリプトコマンド実装は Naninovel.Commands 名前空間の下で定義されています。

カスタムコマンドの追加 ​

独自のカスタムスクリプトコマンドを追加するには、Command から派生した新しいC#クラスを作成し、Execute メソッドをオーバーライドします。作成されたクラスはエンジンによって自動的に検出され、クラス名またはエイリアス(割り当てられている場合)を使用してシナリオスクリプトからコマンドを呼び出すことができます。Naninovelコマンドにエイリアスを割り当てるには、クラスに Alias 属性を適用します。

以下は、シナリオスクリプトから @HelloWorld または @hello として呼び出してコンソールに「こんにちは、世界!」を出力できるカスタムコマンドの例です。オプションの name パラメーター(例:@hello name:Felix)を使用して、「World」の代わりに指定された名前に挨拶することもできます。

cs
using System;
using Naninovel;
using Naninovel.Commands;
using UnityEngine;

[Serializable, Alias("hello")]
public class HelloWorld : Command
{
    public StringParameter Name;

    public override Awaitable Execute (ExecutionContext ctx)
    {
        if (Assigned(Name)) Debug.Log($"Hello, {Name}!");
        else Debug.Log("こんにちは、世界!");
        return Async.Completed;
    }
}

注意

クラスの名前変更、パラメーターの追加または削除、パラメーターの型や属性の変更など、C#コマンドの実装を変更したときは必ず、シナリオスクリプトアセットを再インポートすることを忘れないでください(スクリプトが保存されているフォルダーを右クリックして「Reimport」をクリックします)。これは、シナリオスクリプトが(実行時ではなく)インポート時に解析およびコンパイルされ、C#実装と同期している必要があるためです。

Executeメソッド ​

Execute は、スクリプトプレイヤーによってコマンドが実行されたときに呼び出される非同期メソッドです。コマンドのロジックはここに記述します。エンジンサービス を使用して、エンジンの組み込みシステムにアクセスします。このメソッドが返す Awaitable が完了するまで、シナリオスクリプトの実行は一時停止します。待機を任意にするには、組み込みコマンドと同様に、ブール値の Wait パラメーターを宣言し、非同期ロジックを WaitOrForget メソッドでラップします。

実行コンテキスト ​

Execute メソッドに提供される ExecutionContext ctx 引数に注目してください。非同期操作 ↗ を実行する場合は、各非同期操作の後にキャンセルおよび完了要求がないか ctx.Token 非同期トークンを確認し、それに応じて対応してください。

  • AsyncToken.Canceled は、エンジンが破棄またはリセットされたことを意味します。どちらの場合も、エンジンAPIを使用することは安全ではなくなり、状態の変更は未定義の動作につながります。キャンセルされた場合、コマンド実装は、実行中の処理をすべて破棄して、直ちに AsyncOperationCanceledException をスローすることが期待されます。
  • AsyncToken.Completed は、コマンドがすべての処理をできるだけ早く完了することが期待されていることを意味します。たとえば、アニメーションを実行している場合は、想定されている時間に関係なく、即座に終了させます。これは通常、プレイヤーが Continue 入力をアクティブにしたとき、またはゲームのセーブ操作が開始されたときに発生します。
cs
public override async Awaitable Execute (ExecutionContext ctx)
{
    await PerformSomething();
    // 上記のメソッドの実行中にエンジンが破棄された可能性があります。
    // その場合、次のチェックで例外がスローされます。
    ctx.Token.ThrowIfCanceled();
    // チェック後はエンジンAPIを引き続き使用しても安全です。
    var someUI = Engine.GetService<IUIManager>().GetUI<SomeUI>();
    // 完了が要求された場合は、UIを即座にフェードします。
    var fadeDuration = ctx.Token.Completed ? 0 : 5;
    await someUI.ChangeVisibility(false, fadeDuration, ctx.Token);
    // 上記のメソッドは非同期トークンを受け取ります。そのようなメソッドは
    // 内部でキャンセルを処理するため、後でもう一度確認する必要はありません。
}

実行コンテキストには、コマンドを実行中のスクリプトトラックインスタンスも含まれており、ctx.Track でアクセスできます。再生の制御や、トラックを必要とする他のエンジンAPIの呼び出しには、このインスタンスを使用してください。たとえば、再生を停止するには次のようにします。

cs
public override Awaitable Execute (ExecutionContext ctx)
{
    ctx.Track.Stop();
    return Async.Completed;
}

パラメーターの型 ​

コマンドパラメーターをシナリオスクリプトに公開するには、サポートされている型のいずれかのパブリックフィールドをコマンドクラスに追加します。

フィールドの型値の型スクリプト例
StringParameterStringLoremIpsum, "Lorem ipsum"
LocalizableTextParameterLocalizableText"Lorem ipsum|#id|"
NumberParameterSingle10, 0.525, -55.1
BooleanParameterBooleantrue, false
NamedStringParameterNamedStringScript001.LabelName, .LabelName
NamedNumberParameterNamedNumberYuko.5, Kohaku.-10.25
NamedBooleanParameterNamedBooleanMisaki.false
StringListParameterList<String>Lorem,ipsum,"dolor sit amet"
NumberListParameterList<Single>10,-1,0.105
BooleanListParameterList<Boolean>true,false,true
NamedStringListParameterList<NamedString>Felix.Happy,Jenna.Confidence
NamedNumberListParameterList<NamedNumber>Yuko.5,Misaki.-8
NamedBooleanListParameterList<NamedBoolean>Misaki.false,Kohaku.true

パラメーターエイリアス ​

必要に応じて、[Alias] 属性をフィールドに適用してパラメーターにエイリアス名を割り当てることができます。これにより、シナリオスクリプトでパラメーターを参照するときに、フィールド名の代わりにそのエイリアスを使用できます。

cs
[Alias("myParam")]
public StringParameter MyParameter;
nani
@cmd myParam: value of 'MyParameter' param

プライマリパラメーター ​

パラメーターを識別子なしで指定できるようにするには、[PrimaryParameter] 属性を適用します。各コマンドに設定できるプライマリパラメーターは1つだけです。

cs
[PrimaryParameter]
public StringParameter MyPrimaryParameter;
nani
@cmd value of the primary param

必須パラメーター ​

パラメーターを必須にする(シナリオスクリプトで指定されていない場合にエラーがログに記録されるようにする)には、[RequiredParameter] 属性をフィールドに適用します。属性が適用されていない場合、パラメーターはオプションと見なされます。

cs
[RequiredParameter]
public StringParameter MyRequiredParameter;

オプションパラメーター ​

パラメーターが必須でない場合、シナリオスクリプトで値が割り当てられている場合と割り当てられていない場合があります。HasValue プロパティを使用して、値が割り当てられているかどうかを確認します。あるいは、パラメーターインスタンスを受け取り、指定されたパラメーターがnullではなく値が割り当てられている場合にtrueを返す Assigned() 静的メソッドを使用することもできます。

cs
public StringParameter MyOptionalParameter;
...
if (MyOptionalParameter.HasValue) { }
if (Assigned(MyOptionalParameter)) { }

ローカライズ可能なコマンド ​

コマンドにローカライズ可能なパラメーター(プレイヤーに直接提示されるテキスト)がある場合は、Command.ILocalizable インターフェースを実装して、生成される スクリプトのローカライズ ドキュメントにコマンドが追加されるようにし、パラメーターの型には LocalizableTextParameter を使用します。

cs
public class PrintText : Command, Command.ILocalizable
{
    public LocalizableTextParameter Text;
}

プリロード可能なコマンド ​

コマンドの実行にリソースのロードが必要な場合は、Command.IPreloadable インターフェースを実装して、ゲームのロード時に必要なリソースをプリロードします。詳細については、メモリ管理 ガイドを参照してください。

cs
public class PlayAudioClip : Command, Command.IPreloadable
{
    public StringParameter ClipPath;

    public async Awaitable PreloadResources (ScriptPlaylist playlist)
    {
        if (!Assigned(ClipPath) || ClipPath.DynamicValue) return;
        await Audio.SfxLoader.Load(ClipPath, this);
    }

    public void ReleaseResources (ScriptPlaylist playlist)
    {
        if (!Assigned(ClipPath) || ClipPath.DynamicValue) return;
        Audio.SfxLoader.Release(ClipPath, this);
    }
}

ClipPath.DynamicValue のチェックに注目してください。コマンドの実行時にならないと名前がわからない場合(つまり、パラメーターに シナリオ式 が含まれている場合)はリソースをプリロードできません。この場合、リソースは Execute メソッド内でロードする必要があります。

コマンドの例 ​

すべての組み込みコマンド実装を含むC#スクリプトは、Naninovel/Runtime/Commands パッケージフォルダーにあります。独自のカスタムコマンドを実装する際の参考にしてください。

例

インベントリサンプル には、インベントリシステムのアイテムを追加/削除するカスタムコマンドの例もあります。コマンドの実装は Scripts/Runtime/Inventory/Commands ディレクトリに保存されています。

組み込みコマンドのオーバーライド ​

場合によっては、組み込みNaninovelコマンドをオーバーライドすると便利なことがあります。たとえば、カスタムコマンドを追加せずに @print コマンドの動作を変更して、その変更が 汎用テキスト行 にも反映されるようにしたい場合があります(汎用テキスト行のテキストは内部的にprintコマンドへ変換されます)。

組み込みコマンドをオーバーライドするには、カスタムコマンドを追加し、組み込みコマンドと同じエイリアスを適用します。変更を有効にするには、コマンドをオーバーライドした後にシナリオスクリプトを再インポートします(スクリプトが保存されているフォルダーを右クリックし、「Reimport」をクリックします)。その後、シナリオスクリプトを再生するときに、組み込みコマンドの代わりにカスタムコマンドが自動的に使用されます。

以下は、組み込みの @print コマンドをオーバーライドし、テキストをプレイヤーに表示する前にコンソールへログ出力する例です。

cs
[Serializable, Alias("print")]
public class MyCustomPrintCommand : PrintText
{
    public override Awaitable Execute (ExecutionContext ctx)
    {
        Debug.Log(Text);
        return base.Execute(ctx);
    }
}

ヒント

コマンドとパラメーターには、IDEおよびストーリーエディターでドキュメント、自動補完、高度な診断を提供するためのさまざまなコンテキスト属性を適用できます。使用可能な属性については、IDE拡張機能 ガイドを参照してください。