This document is about: FUSION 2
SWITCH TO

TickTimer

##はじめに

あるロジックを起動する前に、一定時間待機させることがよくあります。TickTimerは、Fusionでこれを行うための安全で便利な、そして帯域幅効率の良い方法です。名前に反して、TickTimerはタイマーではなく、ターゲットティック値を保存し、現在のシミュレーションティックを使ってチェックを実行する構造体です。

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

  • タイマーは時間切れですか?
  • タイマーは動いていますか?
  • タイマーの残り時間は?

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

注意TickTimer.CreateFromSeconds()で初期化した場合でも、_TickTimerはターゲットtickを使用します。TickTimer.CreateFromSeconds(1.37f)で初期化した場合でも、ターゲットtickを使用します。このことと、tickレートを考慮すると、計算されたターゲットtickは、経過した秒数によって正確さを失う可能性があります。

API

  • CreateFromSeconds: 新しい TickTimer を、指定された Seconds の量と現在のシミュレーションティックで計算されたターゲットティックで返す。
  • CreateFromTicks: 新しい TickTimer を返す。 指定された Ticks の量と現在のシミュレーションティックで計算されたターゲットティックを持つ新しい TickTimer を返します。
  • RemainingTime: 残り時間を_S単位で返す。 TickTimer が終了するまでの残り時間を Seconds で返します。
  • RemainingTicks:残り時間を秒単位で返す。TickTimer が終了するまでの残り時間を Ticks で返します。
  • IsRunningTickTimerのターゲットティックが現在のシミュレーションティックより大きい場合にtrueを返す。
  • ExpiredTickTimer が実行中で、ターゲットティックが現在のシミュレーションティックより小さいか等しい場合に真を返す。
  • ExpiredOrNotRunningTickTimerdefaultTickTimer.None、または実行中で、ターゲットtickが現在のシミュレーションtick以下である場合にtrueを返す。

TickTimerのリセット

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

C#

[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 をカスタマイズして簡略化したものです。

C#

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の現在のティックから初期ティックの値を引きます。

C#

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の間の正規化されたfloatで返すには、経過ティック数をタイマーがカウントしているティック数の合計で割ります。

C#

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をこれらの値に使用できるようになりました。

C#

[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);
  }
}
Back to top