4. 最初のスクリプト
フレームワーク全体を解き放つたった 1 つのパターンと、最初に使うことになる 5 つのサービスのコピー&ペースト用スニペット。
4.1 クイックスタート
新しい C# スクリプトを作成し、これを貼り付けて、どのシーンのどの GameObject でもいいので載せて、Play を押してください:
using CommonGameSystem.Core;
using UnityEngine;
public class HelloCgs : MonoBehaviour
{
private void Start()
{
var scheduler = ServiceLocator.Resolve<IScheduler>();
var tween = ServiceLocator.Resolve<ITweenService>();
scheduler.After(1f, () => Debug.Log("One second after Play."));
tween.To(1f, 2f, 0.5f,
scale => transform.localScale = Vector3.one * scale,
EaseType.OutBack);
}
}
オブジェクトはバネのようなオーバーシュートつきで 2 倍のサイズに弾け、1 秒後にメッセージが表示されます。ここにないものに注目してください: マネージャープレハブも、初期化シーンも、セットアップコンポーネントもありません。ブートストラップが、あなたの Start が走る前に 23 のサービスすべてを登録済みだったのです。
4.2 サービス解決の仕組み
すべての CGS サービスには同じ方法でアクセスします: サービスロケーターに、必要なインターフェイスを要求するのです。
var save = ServiceLocator.Resolve<ISaveService>();
これを高速かつ安全に保つルールは 3 つです:
- 早めに解決し、結果をキャッシュする。 サービスは最初のシーンがロードされる前に登録されるので、
AwakeもStartも安全な解決場所です。参照をフィールドに保存して再利用してください —Updateの中でResolveを呼んではいけません。 - 存在しないサービスは例外を投げる。 そのインターフェイスに何も登録されていなければ、
Resolve<T>()は明快な例外を投げます。ソフトに確認したい場合はServiceLocator.TryResolve(out T service)かServiceLocator.IsRegistered<T>()を使ってください。 - 何でも差し替えられる。
ServiceLocator.Replace<T>(instance)は、独自実装でも、何もしない null 版でも、いつでも差し替えられます(第 1 章 1.4 節)。
典型的な利用側コードは次のようになります:
public class GameHud : MonoBehaviour
{
private ISaveService _save; // cached once, used many times
private void Awake()
{
_save = ServiceLocator.Resolve<ISaveService>();
}
}
4.3 最初に使うことになる 5 つのサービス
以下の各スニペットは、4.1 節の using を前提に、MonoBehaviour の中で動作します。
セーブとロード
シリアライズ可能なクラスなら何でもセーブファイルにできます。書き込みはアトミックです — セーブ途中のクラッシュが直前のファイルを壊すことはありません。完全なリファレンス: Save/Load。
[System.Serializable]
public class PlayerData { public int Level; public float Health; }
var save = ServiceLocator.Resolve<ISaveService>();
save.Save("slot0", new PlayerData { Level = 3, Health = 75f });
var result = save.Load<PlayerData>("slot0");
if (result.Status == SaveStatus.Ok)
Debug.Log("Loaded level " + result.Value.Level);
イベント
どんなクラスもイベントになれます。パブリッシャーとサブスクライバーは互いを一切参照しません — 参照するのはイベント型だけです。完全なリファレンス: Event Bus。
public sealed class CoinCollected { public int Amount; }
var events = ServiceLocator.Resolve<IEventBus>();
System.IDisposable ticket = events.Subscribe<CoinCollected>(
e => Debug.Log("Coins gained: " + e.Amount));
events.Publish(new CoinCollected { Amount = 5 });
ticket.Dispose(); // stop listening (do this in OnDestroy)
タイマー
タイマーはスケジュールされた順に発火します。ワンショットタイマーは自分で後始末をします。繰り返しタイマーは、あなたが破棄するまで走り続けます。完全なリファレンス: Scheduler。
var scheduler = ServiceLocator.Resolve<IScheduler>();
scheduler.After(2f, () => Debug.Log("Two seconds later, exactly once."));
System.IDisposable heartbeat =
scheduler.Every(0.5f, () => Debug.Log("Every half second."));
heartbeat.Dispose(); // stop the repeating timer when done
トゥイーン
トゥイーンは、ある数値から別の数値へと値をアニメーションさせ、各ステップをあなたに渡します。デフォルトではトゥイーンはゲームプレイクロック上で動くため、ゲームがポーズすると一緒に停止します。完全なリファレンス: Tween。
var tween = ServiceLocator.Resolve<ITweenService>();
CanvasGroup group = GetComponent<CanvasGroup>();
tween.To(1f, 0f, 0.75f,
alpha => group.alpha = alpha,
EaseType.OutQuad,
onComplete: () => Debug.Log("Fade finished."));
入力
入力は、あなたの入力アクションアセットの名前つきアクションマップを通じて読み取ります。"Gameplay" と "Jump" は、あなた自身のアセットの名前に置き換えてください。InputAction 型のために using UnityEngine.InputSystem; を追加します。完全なリファレンス: Input。
private IInputService _input;
private InputAction _jump;
private void Start()
{
_input = ServiceLocator.Resolve<IInputService>();
_jump = _input.GetAction("Gameplay", "Jump");
}
private void Update()
{
if (_jump != null && _input.WasPressedThisFrame(_jump))
Debug.Log("Jump!");
}
4.4 次に進む先
これで、フレームワーク全体を解き放つたった 1 つのパターンが手に入りました: インターフェイスを解決し、キャッシュし、呼び出す。ここからは:
- サービスリファレンス。 すべてのサービスに専用ページがあります — ドキュメント索引から、またはプロジェクト内の
Assets/CommonGameSystem.Core/Documentation/Modules/配下(例えばSaveLoad.mdやTween.md)から始めてください。各ページは完全な API、よく使うパターン、重要な注意点をカバーしています。 - サンプル。 RPG Starter Sample(第 3 章)は、上記のサービスのいくつかが 1 つの小さなゲームスライスの中で協調する様子を示します。
- このマニュアルの続き。 第 5 章は 5 つのコアコンセプトを説明し、第 6 章はフレームワークをあなた自身のアセットに接続します。
- 変更履歴。 Welcome ウィンドウのクイックリンク(第 3 章)から、ドキュメントと、インストール中のバージョンの変更履歴を開けます。
次へ: 5. コアコンセプト