This document is about: QUANTUM 1
SWITCH TO

Framework

はじめに

ターンベースのフレームワーク は、ターン関連データのロジックを保存および操作するのに役立ちます。

そのほとんどは、Turn Data structインスタンス で発生します。Turn Data structインスタンス は、データアセットを介して 構成可能なパラメーター を持ち、各プレイヤー/エンティティに対し、および/またはグローバルに使用してゲームフローを管理できます。

このフレームワークはQuantum SignalsとEvents を使用して、ゲームのシミュレーションエンジンとレンダリングエンジンをそれぞれ維持し、ターンデータで何が起こっているかを認識します。
それらを利用して、フレームワークをゲームのニーズに統合します。

Quantum Inputsを使用したほうが良い場合もありますが、ターンベースのゲームは、プレイヤーとシミュレーションの相互作用の主な方法としてQuantum Commands を使用するのに適しています。
これらは帯域幅の使用を大幅に節約し、デフォルトでフレームワークで使用されます。

最後に、プレイヤーコマンドを受け取り、ターンクロックを更新するフレームワークシステムがあります。

ターンデータフィールド

Turn Data構造体は、便宜上使用することができる、PlayerEntity への参照を保持します。例えば、このデータが参照するプレイヤーまたはエンティティに簡単にアクセスするためなどです。また、Config アセットインスタンスへの参照も保持します。このインスタンスには、ターン設定可能なパラメーターに関する情報が含まれています(詳細:Turn Configuration)。

すべてのターンには、現在許可されている/有効なインタラクションの種類と、許可されていない/有効でないインタラクションの種類を提案します(デフォルトでは義務付けません)。
フレームワークには、2つの定義済みタイプが含まれています:Play(カードゲームでカードを引くなどのプレイヤーインタラクションが許可されている間に使用されます)、および Countdown(許可されていなくてゲームプレイが保留中に使用されます)です。
既存のタイプを解釈したり、独自のタイプを作成して、ゲームの特性に合わせてフレームワークを調整できます。

各ターンには、現在の ステータス もあります。これは、そのデータに対してどのロジックが作用するかを定義するために使用されます。
フレームワークは、次の3つの事前定義済みステータスを使用します:Active(ターンタイマーが増加し、プレイヤーコマンドが受け入れられる場合)。Inactive(タイマーが増加せず、プレイヤーのコマンドが受け入れられない場合)。Resolving(ゲーム固有のロジックを実行する必要がある場合に、現在のプレイヤーがプレイコマンドを受信すると、有効と無効の間の一時的なステータスを通知します。例:Golfサンプルのボール物理をシミュレートする際)。

ターン Number は、別のターンデータからの統計の蓄積 の際に1増加します。
そうすることにより、グローバルな現在のターン が終了した際に有効なプレイヤーのターンデータ番号を更新できます。
ターン ティック は、グローバルな現在のターン が有効な場合、フレームごとに増加します。
プレイヤーのターンデータインスタンスでは、そのプレイヤーが以前のすべてのターンで有効だったティックを 累積 するために使用されます。

Current Turn は、新しいターンごとにリセットされて現在のプレイヤーのターンを追跡するグローバルターンデータインスタンスです。
終了すると、データはそのプレイヤー自身のターンデータインスタンスに蓄積されます。

ターンはさまざまな理由で終了する可能性があるため、フレームワークはそれらのいくつかを ターン終了理由 として列挙します。ゴルフサンプルのユースケースとして観察されます。

C#

enum TurnType { Play, Countdown }
enum TurnStatus { Inactive, Active, Resolving }
enum TurnEndReason { Time, Skip, Play, Resolved }

struct TurnData
{
  player_ref Player;
  entity_ref Entity;
  asset_ref<TurnConfig> Config;
  TurnType Type;
  TurnStatus Status;
  Int32 Number;
  Int32 Ticks;
}

global
{
  TurnData CurrentTurn;
}

ターンデータメソッド

Turn DataインスタンスがUpdateされ、タイマーを使用(Turn Configurationを確認) してステータスがActiveの場合、Tickは1ずつ増加します
ティックがそのターンの構成アセットで定義されたターン時間に達すると、ターン終了理由としてTimeOn Turn Endedシグナルがトリガーされます。

C#

public void Update(Frame f)
{
  if (Config == null || !Config.UsesTimer || Status != TurnStatus.Active)
  {
    return;
  }
  Ticks++;
  if (Ticks >= Config.TurnDurationInTicks)
  {
    f.Signals.OnTurnEnded(this, TurnEndReason.Time);
  }
}

ターンデータは、別のインスタンスからの 統計を蓄積 し、ターン 番号 を1増やし、インスタンスから ティック を蓄積することもできます。
通常、プレイヤーのターンデータインスタンスは、終了時に global current turn からの統計を蓄積します。

C#

public void AccumulateStats(TurnData from) {
  Ticks += from.Ticks;
  Number++;
}

ターン Set TypeおよびStatus メソッドを使用して、それらを特定の値に設定できます。
Frameが提供され(必須ではない)、値が実際に変更される場合、Eventsが呼び出されて、そのようなことが発生したこと、および/またはターンがアクティブになったことを伝えます。

C#

public void SetType(TurnType newType, Frame f = null)
{
  if (Type == newType)
  {
    return;
  }
  var previousType = Type;
  Type = newType;
  f?.Events.TurnTypeChanged(this, previousType);
}

public void SetStatus(TurnStatus newStatus, Frame f = null)
{
  if (Status == newStatus)
  {
    return;
  }
  var previousStatus = Status;
  Status = newStatus;
  f?.Events.TurnStatusChanged(this, previousStatus);
  if (Status == TurnStatus.Active)
  {
    f?.Events.TurnActivated(this);
  }
}

プレイヤーのターンデータインスタンスは、ゲームの開始時に リセット され、提供されたオーバーロードの1つを使用して Ticks 値をリセットしたり他のインスタンスフィールドを設定できます。
また、ターンの終了時に global current turn をリセットして、他のプレイヤーのターンを追跡する準備をするために使用することもできます。
フレームが提供されている場合(必須ではありません)、そのフレームでTurn Timer Resetイベントが発生します。

C#

public void ResetTicks(Frame f = null)
{
  ResetData(Type, Status, Entity, Player, Config, f);
}

public void Reset(TurnConfig config, TurnType type, TurnStatus status, Frame f = null)
{
  ResetData(type, status, Entity, Player, config, f);
}

public void Reset(EntityRef entity, PlayerRef owner, Frame f = null)
{
  ResetData(Type, Status, entity, owner, Config, f);
}

public void Reset(TurnConfig config, TurnType type, TurnStatus status, EntityRef entity, PlayerRef owner, Frame f = null)
{
  ResetData(type, status, entity, owner, config, f);
}

ターン設定

Quantum アセット は、インデックス付きデータベース内の不変インスタンスとして最終的にデータ駆動型コンテナを定義するための機能です。
次の場合、フレームワークは、ターンに関する情報を保持するTurn Configデータアセットを使用します。タイマーを使用する場合(つまり、ステータスがActiveの場合、Ticks フィールドはフレームごとに増加する)。タイマーを使用するターンが終了したかどうかを追跡するために使用される ティックによるターン期間 が使われる場合。スキップ可能 の場合(つまり、プレイヤーは自分のターンをスキップできる)。
より多くの設定可能なデータを追加して、各ゲームのターン設定を調整する必要があります。

C#

public partial class TurnConfig
{
    public Boolean UsesTimer;
    public Int32 TurnDurationInTicks;
    public Boolean IsSkippable;
}

シグナル

Quantum シグナル は、システム間通信用です。

Turn Ended シグナルは、ターンが特定のターン終了の理由で終了したことを知らせるためにトリガーできます。ゲーム固有のターン制御ロジックをトリガーするために使用する必要があります。例えば、Golfサンプルで次のプレイヤーにターンを渡す場合などです。

Play/Skip Command Received シグナルは、それぞれの有効なコマンドが受信されたときにフレームワークによって発生し、、目的のゲーム固有のロジックをトリガーするために使用できます。例えば、Golfサンプルでボールを打ったり、ターンを終了する場合です。(Systemsのプレイヤーコマンドの有効性の詳細)。

C#

signal OnTurnEnded (TurnData data, TurnEndReason reason);
signal OnPlayCommandReceived (PlayerRef player, PlayCommandData data);
signal OnSkipCommandReceived (PlayerRef player, SkipCommandData data);

イベント

Quantumイベントは、シミュレーションの内部で発生したことをレンダリングエンジンに伝えることを目的としているため、必要に応じて視聴覚フィードバックを返すことができます。
レギュラー/同期/抽象Quantumイベントに関する詳細はこちら.

ターンデータセットメソッド(詳細はこちら:Methods)を介して ターンタイプ/ステータスが変更 されると、そのターンデータインスタンス値と前の タイプ/状態 を伝えるイベントが発生します。
null以外のフレームを渡すReset メソッド を呼び出して ターンタイマーがリセットされる と、そのターンデータインスタンス値を伝えるイベントが発生します。
Set Status メソッドで StatusActive に変更することでターンが有効になった場合、またはターンが特定の理由で終了した場合、そうすることを知らせるイベントが発生します。後者では理由を渡します。
有効Play/Skipコマンド がそれぞれのコマンドSystemで受信されると、そのことを知らせるイベントが発生します。

C#

abstract event TurnEvent                   { TurnData      Turn; }
synced event TurnTypeChanged   : TurnEvent { TurnType      PreviousType; }
synced event TurnStatusChanged : TurnEvent { TurnStatus    PreviousStatus; }
synced event TurnEnded         : TurnEvent { TurnEndReason Reason; }
synced event TurnTimerReset    : TurnEvent { }
synced event TurnActivated     : TurnEvent { }

abstract event CommandEvent              { player_ref Player; }
event PlayCommandReceived : CommandEvent { PlayCommandData Data; }
event SkipCommandReceived : CommandEvent { SkipCommandData Data; }

コマンド

Quantum CommandsはQuantum Inputsに似ていますが、ティックごとに送信する必要はなく、使用する帯域幅も少なくなります。
フレームワークで定義された両方のコマンドは、ゲーム固有のコマンドデータを運ぶためにジェネリック構造体を使用し、それに応じてシリアル化する必要があります。

Play Command は、有効なプレイターンのプレイヤー送信でき、ターン中に行われた決定/動きに関する情報を送信できます。
コマンドのそれぞれのシステムによって受信および検証され、プレイヤーのターンがPlayタイプでActiveであるかどうかが確認されます。

以下のコードでは、Golf Sampleコマンドデータの定義とシリアル化を確認できます。

C#

[Serializable]
public struct PlayCommandData
{
    // game-specific command data here
    public FP Force;
    public FPVector3 Direction;
}

public class PlayCommand : DeterministicCommand
{
    public PlayCommandData Data;

    public override void Serialize(BitStream stream)
    {
    // serialize command data here
      stream.Serialize(ref Data.Force);
      stream.Serialize(ref Data.Direction);
    }
}

有効なプレイターンのプレイヤーはSkipコマンドを送信してスキップすることができます。
コマンドのそれぞれのシステムによって受信され、確認されます。システムはプレイヤーのターンがActiveで、ターンがスキップ可能であるかどうかを確認します。

C#

[Serializable]
public struct SkipCommandData
{
    // game-specific command data here
}

public class SkipCommand : DeterministicCommand
{
    public SkipCommandData Data;

    public override void Serialize(BitStream stream)
    {
      // serialize command data here
    }
}

システム

Quantum システム は、Quantumのクライアントシミュレーションループによるティック更新ごとに実行されるステートレスロジックです。

Play/Skip Command Systems は、現在有効なプレイヤーのPlayおよびSkipコマンドをそれぞれ受信します。
global current turn で参照されるプレイヤーのみがコマンドを受け入れられます。また、global current turnActive な場合に限ります。
また、Playコマンドを受信するときはターンが Play タイプであるかどうか、Skipコマンドを受信するときはターンが is skippable としてマークされているかどうかも確認されます。

Playコマンドを受信すると、global current turn ステータスが Resolving に設定されるため、Ticks タイマーはそれ以上増加せず(ターンは Active ではなくなります)、ゲーム固有のロジックを実行する必要があるかもしれません。

いずれかのコマンドを受信すると、対応するシグナルとイベントがトリガーされる/発生します。

C#

 public unsafe class CommandSystem : SystemBase {
    public override void Update(Frame f) {
      var currentTurn = f.Global->CurrentTurn;
      if (currentTurn.Status != TurnStatus.Active) return;

      var currentPlayer = f.Global->CurrentTurn.Player;

      switch (f.GetPlayerCommand(currentPlayer)) {
        case PlayCommand playCommand:
          if (currentTurn.Type != TurnType.Play) return;
          f.Signals.OnPlayCommandReceived(currentPlayer, playCommand.Data);
          f.Events.PlayCommandReceived(currentPlayer, playCommand.Data);
          break;

        case SkipCommand skipCommand:
          if (!currentTurn.Config.IsSkippable) return;
          f.Signals.OnSkipCommandReceived(currentPlayer, skipCommand.Data);
          f.Events.SkipCommandReceived(currentPlayer, skipCommand.Data);
          break;
      }
    }
  }

Turn Timer System は、ティック更新ごとにglobal current turn'sUpdate methodを呼び出すだけです。

C#

public unsafe class TurnTimerSystem : SystemBase
{
    public override void Update(Frame f)
    {
        f.Global->CurrentTurn.Update(f);
      }
}

Fair Timer

FairTimer.cs はローカルのプレイヤーに クライアントのRTTやインプットオフセットを考慮した より公正で現実的なタイマーを 表示する パターンを表しています。
シミュレーション上のもの、各クライアントで同期実行されている最新のターンタイマーに干渉 しない 点に留意ください。単にラグに応じて変更が生じるプレイヤーに 表示される 値です。これは設定可能な任意の機能です。想定する挙動になるように調整してください。

Fair Timerはゴルフ特有のパターンではありません。タイマーを使用するゲームであればこのパターンのメリットを享受できます。GolfサンプルでのFair Timerソリューションは、ターンベースフレームワークから切り離し、マイナーチェンジを伴って使用できます。

Back to top