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

TickTimer

はじめに

Fusionでは、すぐに使用できるように様々な組み込み済みのNetworkBehaviourが用意されています。

    [Networked]
    public TickTimer Timer { get; set; }

    // move object
    public override void FixedUpdateNetwork() {

        // set timer with seconds
        Timer = TickTimer.CreateFromSeconds(Runner, 1);

        // set timer with ticks
        Timer = TickTimer.CreateFromTicks(Runner, 5);


        // check if timer is running
        if (Timer.IsRunning) {

        }

        // returns nullable int? if this has a value its the tick the timer will expire on
        var targetTick     = Timer.TargetTick;

        // if any remaining ticks returns how many ticks that are remaining, if not returns null
        var remainingTicks = Timer.RemainingTicks(Runner);

        // if the timer has been started and has then expired, is not true if timer has not been started
        if (Timer.Expired(Runner)) {

        }

        // if the timer expired (same as Expired) OR if its not running at all
        if (Timer.ExpiredOrNotRunning(Runner)) {

        }

        // to clear/stop a timer:
        Timer = TickTimer.None;
    }

トップに戻る

NetworkRunner

Fusionの中核となるのがNetworkRunnerです。NetworkRunnerは、ネットワークへの接続を管理し、シミュレーションを制御します。入力の収集からスナップショットの結合、コールバックの呼び出し、SimulationBehavioursのライフサイクルメソッドまで、さまざまな処理を行います。 シーン内のNetworkRunner`は、クライアントとサーバーのそれぞれに1つだけ存在します。

これらのタスクを実行するために、NetworkRunnerはすべてのNetworkObjectNetworkBehaviourSimulationBehaviourを管理します。 Fusionの中核となるのがNetworkRunnerです。NetworkRunnerは、ネットワークへの接続を管理し、シミュレーションを制御します。入力の収集からスナップショットの結合、コールバックの呼び出し、SimulationBehavioursのライフサイクルメソッドまで、さまざまな処理を行います。 シーン内のNetworkRunner`は、クライアントとサーバーのそれぞれに1つだけ存在します。

これらのタスクを実行するために、NetworkRunnerはすべてのNetworkObjectNetworkBehaviourSimulationBehaviourを管理跡します。

トップに戻る

プロパティ

すべての NetworkBehaviour は、Runner プロパティを介して現在の NetworkRunner にアクセスでき、ランナー自体もいくつかの重要なシステムプロパティを公開します。

  • IsServer: このランナーが権威あるサーバーを表している場合はtrue。
  • Stage: シミュレーションの現在のステージ。シミュレーションが次の状態を予測している場合には Forward 、サーバーのアップデートに合わせて古い状態を再シミュレーションしている場合には Resimulate になります。なお、Resimulateはサーバー上や、シミュレーションが常にForwardであるClient-Authorityモードでは発生しません。

トップに戻る

コールバック

NetworkRunnerでは、INetworkRunnerCallbacksインターフェースを実装し、NetworkRunner.AddCallbacks()を呼び出してランナーに登録することで、アプリケーションが重要なネットワーク関連イベントにフックすることができます。

注: FusionはINetworkRunnerCallbacksインターフェイスを実装したSimulationBehaviourをコールバックターゲットとして自動的に登録します。

最も重要なコールバックは、OnServerConnectedOnPlayerJoinedで、ゲームは初期のプレイヤーオブジェクトをここで生成します。

public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
    _players[player] = runner.Spawn(_playerPrefab, Vector3.zero, Quaternion.identity, player);
}

利用可能なコールバックの詳細については、APIリファレンスを参照してください。

トップに戻る

GameMode

GameModeは、ローカルピアがどのように振る舞うかを定義します。GameModeは、NetworkRunner.StartGame()メソッドのパラメータとして渡されます。

  • client: クライアントとして動作し、ローカルプレイヤーを作成して、クライアントホスト(クラウドシェアリング)または専用ホスト(サーバーベース)に接続します。
  • host: サーバーとして動作し、ローカルプレイヤーを作成します (サーバー + クライアント)
  • server: 専用のサーバーとして動作し、プレイヤーはいません。
  • shared: クライアントとして動作し、ローカルプレイヤーを作成してFusion Plugin Serverに接続します。
  • single: "サーバー "として動作し、ローカルプレイヤーを作成します。

トップに戻る

NetworkTransform

NetworkTransformは、オブジェクトの実際のローカルなTransformとそのシミュレートされた状態を補間することで、単純なキネマティックオブジェクトを管理します。

トップに戻る

NetworkRigidbody

リジッドボディの場合、NetworkRigidbodyは、単に古い状態を補うだけでなく、物理オブジェクトの予測可能な性質を利用して、より正確なローカル位置を推定します。

トップに戻る

NetworkCharacterController

最も不安定なオブジェクトはプレイヤーが直接操作するもので、一般的にCharacter Controllerと呼ばれています。Fusionでは、このようなケースに対応するために、NetworkCharacterControllerを用意しています。

事前にビルドされたNetworkCharacterControllerには、一般的な動作が含まれているので、素早くプロトタイピングを行うことができます。しかし、Character Controllerの実装はゲームによって大きく異なるため、万能なCharacter Controllerは存在しません。

そのため、ゲームを制作する際には、NetworkCharacterControllerで使用されている2つのコアメソッド Move()ComputeRawMovement()のソースコードに目を通し、代替となるカスタムキャラクターコントローラを作成するためのヒントを得ることをお勧めします。

トップに戻る

ComputeRawSteer()

これはあくまでも参考実装です。

ComputeRawSteer()は内部メソッドで、キャラクターが現在行っている動きの種類に基づいて、動きの計算の大部分を行います。構築済みの NetworkCharacterControllerでは、Move()は、入力する構造体への参照を渡すことにより、ComputeRawMovement()からmovementPack値を要求します。

void ComputeRawSteer(ref Movement movementPack, float dt) {
  Grounded = movementPack.Grounded;

  float minYSpeed = -100;
  float maxYSpeed = 100;

  var current = Velocity;

  switch (movementPack.Type) {
    case MovementType.FreeFall:

      current.y -= Config._gravityStrength * dt;
      if (!Config.AirControl || movementPack.Tangent == default(Vector3)) {
        current.x = Mathf.Lerp(current.x, 0, dt * Config.Braking);
        current.z = Mathf.Lerp(current.z, 0, dt * Config.Braking);
      } else {
        current += movementPack.Tangent * Config.Acceleration * dt;
      }

      break;

    case MovementType.Horizontal:
      // apply tangent velocity
      current += movementPack.Tangent * Config.Acceleration * dt;

      var tangentSpeed = Vector3.Dot(current, movementPack.Tangent);

      // lerp current velocity to tangent
      var tangentVel = tangentSpeed * movementPack.Tangent;
      var lerp       = Config.Braking * dt;

      current.x = Mathf.Lerp(current.x, tangentVel.x, lerp);
      current.z = Mathf.Lerp(current.z, tangentVel.z, lerp);

      // we only lerp the vertical velocity if the character is not jumping in this exact frame,
      // otherwise it will jump with a lower impulse
      if (Jumped == false) {
        current.y = Mathf.Lerp(current.y, tangentVel.y, lerp);
      }

      // clamp tangent velocity with max speed
      if (tangentSpeed > MaxSpeed) {
        current -= movementPack.Tangent * (tangentSpeed - MaxSpeed);
      }

      break;

    case MovementType.SlopeFall:
      current   += movementPack.SlopeTangent * Config.Acceleration * dt;
      minYSpeed =  -Config.MaxSlopeSpeed;
      break;

    case MovementType.None:
      var lerpFactor = dt * Config.Braking;

      if (current.x != 0) {
        current.x = Mathf.Lerp(current.x, default, lerpFactor);
        if (Mathf.Abs(current.x) < float.Epsilon) {
          current.x = 0;
        }
      }

      if (current.z != 0) {
        current.z = Mathf.Lerp(current.z, default, lerpFactor);
        if (Mathf.Abs(current.z) < float.Epsilon) {
          current.z = 0;
        }
      }

      // we only lerp the vertical velocity back to 0 if the character is not jumping in this exact frame,
      // otherwise it will jump with a lower impulse
      if (current.y != 0 && Jumped == false) {
        current.y = Mathf.Lerp(current.y, default, lerpFactor);
        if (Mathf.Abs(current.y) < float.Epsilon) {
          current.y = 0;
        }
      }

      minYSpeed = 0;
      break;
  }

  // horizontal is clamped elsewhere
  if (movementPack.Type != MovementType.Horizontal) {
    Vector2 h = new Vector2(current.x, current.z);
    if (h.sqrMagnitude > MaxSpeed * MaxSpeed) {
      h = h.normalized * MaxSpeed;
    }

    current.x = h.x;
    current.y = Mathf.Clamp(current.y, minYSpeed, maxYSpeed);
    current.z = h.y;
  }

  Velocity = current;
  // set jump state
  Jumped = false;
}

トップに戻る

Move()

これはあくまでも参考実装です。

これは、完全な Move() 関数の基本的な実装です。移動クエリを実行し、その結果を使用して新しい速度を計算してから、貫通補正+速度積分を変換位置に適用します。 回転は変更されません。

  • direction: 意図された移動方向で、移動クエリと加速の対象となります。
  • callback:任意のカスタムコールバックオブジェクトです。
  • layerMask: 任意のレイヤーマスクです。渡されない場合は、configのデフォルトのものが使用されます。
public void Move(Vector3 direction, ICallbacks callback = null, LayerMask? layerMask = null) {

    var dt           = Runner.DeltaTime;
    var movementPack = ComputeRawMovement(direction, callback, layerMask);

    ComputeRawSteer(ref movementPack, dt);

    var movement = Velocity * dt;
    if (movementPack.Penetration > float.Epsilon) {
      if (movementPack.Penetration > Config.AllowedPenetration) {
        movement += movementPack.Correction;
      } else {
        movement += movementPack.Correction * Config.PenetrationCorrection;
      }
    }

    _transform.position += movement;

    #if DEBUG
    LastMovement = movementPack;
    #endif
}

トップに戻る

NetworkMechanimAnimator

NetworkMechanimAnimatorは、関連付けられたUnity mechanim Animatorが持つパラメータの値を同期させます。

注意: アニメーション自体を同期させるわけではありません。

トップに戻る

NetworkObjectPool

実行時のメモリ割り当てと、ガベージコレクションを削減するために、Unityのすべてのゲームは、古いゲームオブジェクトを破棄せずに再利用できるように何らかの形でオブジェクトプーリングを使用する必要があります。ネットワークオブジェクトも例外ではありません。

すべてのゲームはそれぞれ異なるニーズを持っているので、Fusionには(Unityと同様)ビルトインのオブジェクトプーリングはありません。代わりに2つのフックが用意されています。1つはプールからオブジェクトを取得するフック、もう1つは使用したオブジェクトをプールに戻すフックです。

トップに戻る

NetworkSceneManager

トップに戻る

NetworkEvents

NetworkRunner.AddCallbacks()の代わりに NetworkEventsを使用して、Unityインスペクターでイベントハンドラーを直接接続することができます。 コンポーネントを NetworkObjectに追加し、ドラッグアンドドロップを使用して個々のイベントハンドラーを登録するだけです。

NetworkEventsを使用する必要はなく、ほとんどのゲームでは必要ありません。Unityシーンからネットワークイベントを構成する必要があるまれなケースでの利便性のために含まれています。

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