This document is about: QUANTUM 1
SWITCH TO

コマンド

イントロダクション

SDK最小バージョン: 1.2.3

QUANTUMコマンドとは、Quantumの標準APIへの入力データパスです。QUANTUMインプットと似ていますが、毎チックごとに送信される必要は ありません

QUANTUMコマンドはリライアブルです。サーバーは時間に基づいてコマンドを無視することはありませんが、ローカルのクライアントが(コマンドを生成したそのクライアントでさえも)シミュレーションの一部となるチックを予測できないトレードオフを伴います。
開発者は必要であればビジュアル予測を表示できますが、シミュレーションがコマンドを受信するのはサーバーがコマンドをチックの一部だと確認してからになります。

コマンドはPhoton.Deterministic.DeterministicCommandから継承された通常のC#クラスとして実装されています。
コマンドには、シリアル化できるデータ全てが含まれています。

Quantum Command Sample
サンプルコマンド

ゲームプレイロジックに影響を与えたり、それを実装したり、またはquantum.stateプロジェクトの内部にコマンドを実装したりするデータを含む場合、コマンドをquantum.systemsプロジェクトの一部として作成します。

Quantumシステムと同様に、ランタイム時に使用可能にするためにはコマンドもCommandSetup.cs内に含まれている必要があります。以下を参照してください:

Quantum Command Setup
CommandSetup.csでコマンドを設定する

コマンドをサーバーに送信する

コマンドはUnity内のどこからでも送信可能です:

C#

RemoveUnitCommand command = new RemoveUnitCommand();
command.CellIndex = 42;
QuantumRunner.Default.Game.SendCommand(command);

SendCommand()には2つのオーバーロードがあります。

C#

void SendCommand(DeterministicCommand command);
void SendCommand(Int32 player, DeterministicCommand command);

同じマシンで管理するマルチプレイヤーの場合、プレイヤーインデックス(PlayerRef)を指定します。
1人のローカルプレイヤーのみで行うゲームの場合、プレイヤーインデックスのフィールドは空欄で構いません。

シミュレーションからコマンドをポーリングする

シミュレーションポール内でコマンドの受信・処理を行うには、対象のプレイヤーのフレームを以下のようにします:

C#

RemoveUnitCommand command = f.GetPlayerCommand(playerRef) as RemoveUnitCommand;
if (command != null) {
  // execute command
}

APIはコールバックメカニズムや特定のデザインパターンを強化(または実装)するものではありません。どう解釈するかの選択は開発者にゆだねられています(例えばシグナルへのコード化、Chain of Responsibilityの使用、APIのメソッドとしてのコマンド実行の実装など)。

重要: プレイヤーごと、チックごとに添付されるのは1つのコマンドだけです。チックごとに複数のコマンドを与える場合は、"CompoundCommand"クラスを作成して、数々の子コマンドをコード化します(提供されているBitStreamでシリアル化するかは開発者次第です)。

QuantumのCompound Commands

複数のDeterministic Commandsを 毎チックごとに 送信する場合、通常それらのコマンドはすべて同じチックでシミュレーションに到達しません。連続したチックで別々にシミュレーションに到達します。

Compound Commandsクラスを使用すると、一度のチックで多くのコマンドを送受信することができます。コマンドの種類が異なる場合であっても使用できます。

Compound Commandsの使用にあたってはじめに、quantum_code内でクラスを宣言します。どこでも構いません( quantum_system または quantum_state)。

C#

    namespace Quantum {
      public class CompoundCommands : DeterministicCommand {

        public List<DeterministicCommand> Commands = new List<DeterministicCommand>();
        private int listCount = 0;

        public override void Serialize(BitStream stream) {
          listCount = Commands.Count;
          stream.Serialize(ref listCount);

          if (stream.Reading) {
            Commands.Clear();
          }

          for (var i = 0; i < listCount; i++) {
            if (stream.Reading) {
              DeterministicCommand cmd;
              QuantumGame.Instance.Session.CommandSerializer.ReadNext(stream, out cmd);
              Commands.Add(cmd);
            } else {
              if (Commands[i] != null)
                QuantumGame.Instance.Session.CommandSerializer.PackNext(stream, Commands[i]);
            }
          }
        }
      }
    }

このクラスは、一連のその他のコマンドを含む単一のコマンドを扱います。そのために、今後新しいコマンドを挿入し、またシリアル化・非直列化をおこなうコマンド一覧があります。

クラスの宣言のほか、通常のコマンドと同じようにCommandSetupクラスへのCompoundCommandsの追加も必要です。

Unityでは、毎チック複数のコマンドを送信する先には新しいCompoundComponentが必要になります。独自のカスタムコマンドを作成してカスタム情報を埋め、コマンドの送信前にコマンドリストにカスタムコマンドを追加します。

C#

    public class SampleCompoundCommands : MonoBehaviour {
        void Update () {
            if (UnityEngine.Input.anyKeyDown) {
                CompoundCommands compoundCommands = new CompoundCommands();

                BuyUnitCommand buyUnitCommand = new BuyUnitCommand();
                buyUnitCommand.UnitID = 0;
                compoundCommands.Commands.Add(buyUnitCommand);

                AttackCommand attackCommand = new AttackCommand();
                attackCommand.SelectedPosition = Vector.One;
                compoundCommands.Commands.Add(attackCommand);

                QuantumRunner.Default.Game.SendCommand(compoundCommands);
            }
        }
    }

いつでもコマンドを送信できます。例えば、Compound Commandsに追加されたコマンドがあるかどうか確認を行うマネージャークラスを別個に用意することもできます。コマンドを送信して、クリアします。以下を参照してください。:

C#

    if (compound.Commands.Count > 0) {
        game.SendCommand(player, compound);
        compound.Commands.Clear();
    }

これで、あとはシミュレーションでCompoundCommandsを受け取り、読み取りに使用するパターンを決定するだけになりました。一例として、システム内で以下を行います。:

C#

    var compound = f.GetPlayerCommand(player) as CompoundCommand;
    if (compound != null) {
        for (int i = 0; i < compound.listCount; i++) {
            var command = compound.Commands[i];
            // do a switch case over command types
            // or activate signals so other systems know that a specific command arrived
            // or better: do a polymorphic Execute method inside the command itself
            // or any other pattern to externalize the execution taking into consideration the concrete class of the actual internal instances;
        }
    }
Back to top