TickTimer
概述
在觸發某些邏輯之前等待一段時間通常是有用的。TickTimer是Fusion中一種安全、方便、頻寬高效的方法。儘管它的名字是TickTimer,但它並不是一個真正的計時器,而是一個存儲目標刷新值並使用當前模擬刷新運行檢查的結構。
使用當前刷新(來自NetworkRunner)和目標刷新(在初始化TickTimer時儲存),TickTimer可以提供與任何其他計時器非常相似的資訊,並回答以下問題:
- 計時器到期了嗎?
- 計時器在運行嗎?
- 還剩多少時間/多少刷新?
由於TickTimer使用目標刷新,而不是遞增或遞減浮點數或整數,因此當它作為[Networked]遊戲狀態的一部分被包含時,它使用的頻寬更少,因為它不會改變,且計時器邏輯是本機的。
注意:TickTimer使用目標刷新,即使在用TickTimer.CreateFromSeconds()初始化它時也是如此。考慮到這一點和刷新率,計算出的目標刷新,可能會因經過的秒數而失去一些準確性,例如TickTimer.CreateFromSeconds(1.37f)。
API
- CreateFromSeconds:傳回一個新的- TickTimer,其中包含使用提供的 秒 數和當前模擬刷新所計算的目標刷新。
- CreateFromTicks:傳回一個新的- TickTimer,其中包含使用提供的 刷新 數和當前模擬刷新所計算的目標刷新。
- RemainingTime:傳回- TickTimer到期前的剩餘時間(以 秒 為單位)。
- RemainingTicks:傳回 刷新 中的剩餘時間,直到- TickTimer到期。
- IsRunning:如果- TickTimer目標刷新大於當前模擬刷新,則傳回真。
- Expired:如果- TickTimer正在運行並且目標刷新小於或等於當前模擬刷新,則傳回真。
- ExpiredOrNotRunning:如果- TickTimer是- default、- TickTimer.None,或正在運行且目標刷新小於或等於當前模擬刷新,則傳回真。
重置TickTimer
TickTimer到期後,每當模擬刷新大於它存儲的目標刷新 後,它都會傳回真。為了只得到一次,在這個條件被評估為真的第一個刷新後重置TickTimer是有用的。這可以透過將TickTimer設定為TickTimer.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的簡單性,很容易建立它的自訂版本並實作更多或不同的功能性。
以下兩個示例-計數和標準化時間-只需在建立計時器的那一刻新增初始刷新即可。
注意:以下程式碼是原始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之間的標準化浮點數,請將經過的刷新數除以計時器正在計數的刷新總數。
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);
  }
}