Skip to content

エンジンサービス

エンジン機能のほとんどは、エンジンサービスを介して実装されます。 エンジンサービスは IEngineService インターフェースの実装であり、naninovelスクリプトの実行、アクターの管理、ゲームのセーブロードなど、特定のジョブを処理します。

エンジンシステムとやり取りする場合は、エンジンサービスを使用することをお勧めします。エンジンサービスへの参照は、静的メソッド Engine.GetService<TService>() で取得できます。ここで TService は、参照するサービスのタイプ(インターフェース)です。 たとえば、 IScriptPlayer サービスを取得するには:

csharp
var player = Engine.GetService<IScriptPlayer>();
player.Stop();

以下のサービスが利用可能です:

サービスインターフェース説明
IBackgroundManager背景 アクターの管理
ICharacterManagerキャラクター アクターの管理
IChoiceHandlerManager選択肢ハンドラー アクターの管理
ITextPrinterManagerテキストプリンター アクターの管理
IAudioManagerオーディオ: SFXBGMボイスの管理
IInputManagerユーザー 入力処理の管理
ILocalizationManagerローカライズ アクティビティの管理
ITextManagerテキスト管理 機能を制御
IMoviePlayerムービー 再生を制御
IScriptManagerNaninovel スクリプト リソースの管理
IScriptPlayerNaninovel スクリプト 実行を制御
ICameraManagerシーンのレンダリングに必要なカメラやその他のシステムを管理
IResourceProviderManagerIResourceProvider オブジェクトを管理
IStateManagerIEngineService関連の永続的なデータの逆シリアル化を処理。 セーブロードシステム ゲームステートにAPIを提供。
IUIManagerIManagedUI オブジェクトを管理し、カスタムUI 機能を制御
ICustomVariableManagerカスタム変数 へのアクセスと編集を可能にする
ISpawnManager@spawn コマンドで生成されたオブジェクトを管理
IUnlockableManager収集アイテム (CGやムービーギャラリー, tipsなど) を管理

サービスの組み込み実装は、 Naninovel/Runtime に格納されているランタイムソースコードにあります。

カスタムサービスの追加

新しいカスタムエンジンサービスを追加するには、IEngineService インターフェースを実装し、実装クラスに InitializeAtRuntime 属性を追加します。実装のインスタンスはエンジンの初期化中に自動的に作成され、Engine.GetService<TService>() APIを介して利用できるようになります。

InitializeAtRuntime 属性の InitializationPriority 引数を使用して、他のサービスの前後にカスタムサービスを強制的に初期化できます。値を小さくすると、初期化キュー内の他のサービスの前にプッシュされます。逆も同様です。

自動的にインスタンス化するには、サービス実装に互換性のあるコンストラクター(またはデフォルトのコンストラクター)が必要です。以下の引数(任意の順序)を使用できます:

  • 任意の数の他のサービス (IEngineService-派生)
  • 任意の数の構成オブジェクト (Configuration-派生)
  • Unityの "MonoBehavior" プロキシーオブジェクト (IEngineBehaviour-派生)

コンストラクタで他のサービスを使用するのは安全ではないので、注意してください。代わりに、 InitializeServiceAsync メソッドで他のサービスを使用する必要がある初期化アクティビティを実行します。サービスにアクセスするときに必要なサービスが確実に初期化されるようにするには、それらをサービスコンストラクターにリストします(初期化キューは、コンストラクターの引数に基づいてトポロジ的にソートされます)。

カスタムサービスに永続的なステートがあり、他のエンジンサービスで非/シリアル化したい場合は、 IStatefulService<TState> インターフェイスを実装します。ここで、TState は、GameStateMapGlobalStateMap、または SettingsStateMapです。これはステートをゲームセッション固有のもの、グローバルステートまたは、設定で保存するかによって決まります。必要に応じて、1つのサービスに3つすべてのインターフェースを実装することができます。さまざまなタイプのエンジン状態の詳細については、ステート管理ガイドを参照してください。

以下は、いくつかの使用上の注意を伴うカスタムエンジンサービス実装の例です:

csharp
using Naninovel;
using UniRx.Async;
using UnityEngine;

[InitializeAtRuntime]
public class CustomService : IEngineService
{
    private readonly InputManager inputManager;
    private readonly ScriptPlayer scriptPlayer;

    public CustomService (InputManager inputManager, ScriptPlayer scriptPlayer)
    {
        // サービスはここではまだ初期化されていない可能性があるため、
        // 使用しないでください。
        this.inputManager = inputManager;
        this.scriptPlayer = scriptPlayer;
    }

    public UniTask InitializeServiceAsync ()
    {
    	// ここでサービスを初期化します。
        // これで、コンストラクターでリクエストされたサービスを使用しても安全です。
        Debug.Log(inputManager.ProcessInput);
        Debug.Log(scriptPlayer.PlayedScript);
        return UniTask.CompletedTask;
    }

    public void ResetService ()
    {
        // ここでサービスステートをリセットします。
    }

    public void DestroyService ()
    {
        // サービスを停止し、使用されているリソースをここで解放します。
    }
}

前述のサービスの場合、次の方法でエンジンAPIを介して取得できます:

csharp
var customService = Engine.GetService<CustomService>();

EXAMPLE

アイテムのリソースとインベントリUIの構成を管理するカスタムエンジンサービスを追加する別の例は、GitHubのインベントリサンプルプロジェクト ↗ にあります。

具体的には、カスタムエンジンサービスは InventoryManager.cs ↗ ランタイムスクリプトを介して実装されます。

組み込みサービスの上書き

すべての組み込みサービスは、エンジンのソースコード内のインターフェイスを介して参照されるため、カスタム実装で入れ替えることができます。

カスタムサービスは上記と同じ方法で追加しますが、IEngineService の代わりに具象エンジンインターフェースを実装し、InitializeAtRuntime 属性で上書きするタイプ(インターフェースではなく実装タイプ)を指定します。すると、組み込みサービスの代わりにカスタム実装が初期化されます。

以下は、ダミーの IInputManager 実装の例です。これは何もしませんが、いずれかのメソッドが呼び出されるとログに記録します。

csharp
using Naninovel;
using Naninovel.UI;
using UniRx.Async;
using UnityEngine;

[InitializeAtRuntime(@override: typeof(InputManager))]
public class CustomInputManager : IInputManager
{
    public InputConfiguration Configuration { get; }
    public bool ProcessInput { get; set; }

    public CustomInputManager (InputConfiguration config)
    {
        Configuration = config;
    }

    public UniTask InitializeServiceAsync ()
    {
        Debug.Log("CustomInputManager::InitializeServiceAsync()");
        return UniTask.CompletedTask;
    }

    public void ResetService ()
    {
        Debug.Log("CustomInputManager::ResetService()");
    }

    public void DestroyService ()
    {
        Debug.Log("CustomInputManager::DestroyService()");
    }

    public IInputSampler GetSampler (string bindingName)
    {
        Debug.Log($"CustomInputManager::GetSampler({bindingName})");
        return default;
    }

    public void AddBlockingUI (IManagedUI ui, params string[] allowedSamplers)
    {
        Debug.Log($"CustomInputManager::AddBlockingUI({ui.GetType().Name})");
    }

    public void RemoveBlockingUI (IManagedUI ui)
    {
        Debug.Log($"CustomInputManager::RemoveBlockingUI({ui.GetType().Name})");
    }
}

これで、Engine.GetService<IInputManager>() から入力マネージャーが要求されると、組み込みの Naninovel.InputManager ではなく、カスタム実装が提供されます。