このページは編集中です。更新が保留になっている可能性があります。

TickTimer

はじめに

あるロジックをトリガーする前に、一定時間待機させることは有用です。Fusionでこのような処理を行うには、安全で便利、かつ効率的な方法としてTickTimerがあります。TickTimerという名前ですが、実際にはタイマーではなく、ターゲットティック値を保存し、現在のシミュレーションティックを使ってチェックを実行する構造体です。

現在のティック(NetworkRunner から取得した)とターゲットティック(TickTimer の初期化時に保存した)を使って、TickTimer は他のタイマーと同じように情報を提供し、次のような質問に答えることができます。

  • タイマーが切れましたか?
  • タイマーは作動していますか?
  • 残り時間/残りティック数は?

TickTimer は float や int を増減させるのではなく、ターゲットの tick を使用するので、[Networked] ゲームステートに含まれる場合は、タイマーのロジックがローカルで変化しないため、使用する帯域幅が少なくて済みます。

: TickTimerTickTimer.CreateFromSeconds() で初期化した場合でもターゲットのティックを使用します。この点とティックレートを考慮すると、例えば TickTimer.CreateFromSeconds(1.37f). のように、経過秒数によって計算されたターゲットティックが少し精度を失う可能性があります。

トップに戻る

API

  • CreateFromSeconds: 指定された Seconds の量と現在のシミュレーションの目盛りを使ってターゲット目盛りを計算し、新しい TickTimer を返します。
  • CreateFromTicks: 指定された Ticks と現在のシミュレーションtickを使用して、ターゲットのtickを計算した新しい TickTimer を返します。
  • RemainingTime: TickTimer が終了するまでの残り時間を Seconds で返します。
  • RemainingTicks: TickTimer が終了するまでの残り時間を Ticks で返します。
  • IsRunning: TickTimer のターゲットティックが現在のシミュレーションティックより大きい場合、trueを返します。
  • Expired: TickTimer が実行中で、ターゲットtick が現在のシミュレーションtick よりも小さいか等しい場合に真を返します。
  • ExpiredOrNotRunning: TickTimerdefault, TickTimer.None, または実行中で、ターゲットtickが現在のシミュレーションtickより小さいか等しい場合に true を返します。

トップに戻る

TickTimer をリセットする

TickTimerは、シミュレーションティックが保存されたターゲットティックより大きくなった後、tick毎にtrueを返します。これを一度だけ得るには、この条件がtrueと評価された最初のtickの後に TickTimer をリセットすることが有効です。これは、TickTimerTickTimer.None または default に設定することで可能です。

[Networked] TickTimer timer { get; set; }

void FixedUpdateNetwork()
{
  if (timer.Expired(Runner))
  {
    // Execute Logic

    // Reset timer
    timer = TickTimer.None;
    // alternatively: timer = default.

    Debug.Log("Timer Expired");
  }
}

トップに戻る

カスタム機能の作成

TickTimer はシンプルな機能であるため、そのカスタムバージョンを作成し、より多くの、あるいは異なる機能を実装することは簡単です。 以下の2つの例 - カウントアップと時間の正規化 - は、タイマーが作成された瞬間に最初の目盛りを追加するだけで 実現できます。

: 以下のコードは、オリジナルの TickTimer をカスタマイズして簡略化したもので、カスタムバージョンで実装可能な機能を紹介しています

public struct CustomTickTimer : INetworkStruct
{
  private int _target;
  private int _initialTick;

  public bool Expired(NetworkRunner runner) => runner.IsRunning && _target > 0
    && (Tick) _target <= runner.Simulation.Tick;

  public bool IsRunning => _target > 0;

  public static CustomTickTimer CreateFromTicks(NetworkRunner runner, int ticks)
  {
    if (runner == false || runner.IsRunning == false)
      return new CustomTickTimer();

    CustomTickTimer fromTicks = new CustomTickTimer();
    fromTicks._target = (int) runner.Simulation.Tick + ticks;
    fromTicks._initialTick = runner.Simulation.Tick;
    return fromTicks;
  }

  public float NormalizedValue(NetworkRunner runner)
  {
    if (runner == null || runner.IsRunning == false || IsRunning == false)
      return 0;

    if (Expired(runner))
      return 1;

    return ElapsedTicks(runner) / (_target - (float)_initialTick);
  }

  public int ElapsedTicks(NetworkRunner runner)
  {
    if (runner == false || runner.IsRunning == false)
      return 0;

    if (IsRunning == false || Expired(runner))
      return 0;

    return runner.Simulation.Tick - _initialTick;
  }
}

トップに戻る

カウントアップ

タイマーが作成されてから経過したティック数を取得するには、NetworkRunnerの現在のティックから最初のティックの値を引きます。

public int ElapsedTicks(NetworkRunner runner)
{
  if (runner == false || runner.IsRunning == false)
      return 0;

  if (IsRunning == false || Expired(runner))
    return 0;

  return runner.Simulation.Tick - _initialTick;
}

トップに戻る

0と1の間の正規化された値

タイマーの現在の進行状況を0と1の間の正規化された浮動小数点数で返すには、経過したティック数をタイマーがカウントしている総ティック数で割ります。

public float NormalizedValue(NetworkRunner runner)
{
  if (runner == null || runner.IsRunning == false || IsRunning == false)
    return 0;

  if (Expired(runner))
    return 1;

  return ElapsedTicks(runner) / (_target - (float)_initialTick);
}

これで、CustomTickTimer を使ってそれらの値を表示することができるようになりました。

[Networked]
public CustomTickTimer MyTickTimer { get; set; }

public void StartTimer()
{
  if (Runner.IsServer)
  {
    MyTickTimer = CustomTickTimer.CreateFromTicks(Runner, 120);
  }
}

public override void FixedUpdateNetwork()
{
  Debug.Log($"Elapsed {MyTickTimer.ElapsedTicks(Runner)} ticks.");
  Debug.Log($"Normalized Value {MyTickTimer.NormalizedValue(Runner)}.");

  if (MyTickTimer.Expired(Runner))
  {
    // Execute Logic

    // Reset timer
    MyTickTimer = default;

    Debug.Log("Timer Finished on tick: " + Runner.Simulation.Tick);
  }
}


ドキュメントのトップへ戻る