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

Fusion 104 - 物理

概要

Fusion 104では、サーバーオーソリテーティブゲームでFusionがどのようにPhysXと関わっていくのかを検証します。

このセクションの最後には、プロジェクトでプレイヤーが物理制御のあるボールをスポーンしたり使用したりできるようになります。

本トピックの詳細説明についてはマニュアルを参照ください

トップに戻る

セットアップ

ホストモードでは、Fusionはホストが物理シミュレーションを実行しクライアントが後に続きますが、アプリケーションがクライアントに物理制御オブジェクトでさえも予測を許可するオプションがあります。

この機能をオンにするには、Fusionのメニューに移動し、Network Project Configを選択します。するとインスペクターでFusionのコンフィグファイルが開きます。Server Physics Modeの下でClient Predictionを選択します。

クライアント予測を有効化すると計算コストはかかりますが、より正確な動きが得られます。

トップに戻る

物理オブジェクト

ネットワークされ、PhysX制御されているオブジェクトのプレハブは通常のUnity PhysXオブジェクトと同様のRigidbodyを使用しますが、別のFusionコンポーネントでNetworkRigidbodyというビジュアル子オブジェクトを同期します。これは、ネットワーキングが続く限り、NetworkTransformに置き換わります。

  1. Unity Editorで空の新しいGameObjectを作成する
  2. GameObjectの名前をPhysxBallにする
  3. 新しいNetworkRigidbodyコンポーネントを追加する
  4. FusionがNetworkObjectコンポーネントが欠けているという警告を表示するので、続けてAdd Network Objectを押す。PhysXシミュレーションで必要なため、Fusionは自動的に通常のUnity RigidBodyも追加する
  5. Interpolation Data SourcePredictedへ変更しWorld Spaceに設定する
  6. Sphereの子をPhysxBallに追加する
  7. 子のサイズを全方向において0.2まで下げる
  8. 子オブジェクトを親オブジェクトのNetworkTransformコンポーネントのInterpolationTarget内にドラッグする
  9. Sphereからコライダーを削除する
  10. 親オブジェクトで新しいsphereコライダーを、子オブジェクトを完全に覆うように半径0.1で作成する
  11. ゲームオブジェクトに新しいスクリプトを追加し、PhysxBall.csと名前を付ける
  12. 全てのオブジェクトをプロジェクトフォルダにドラッグしプレハブを作成する
  13. シーンを保存してネットワークオブジェクトをベイクしシーンからプレハブインスタンスを削除する

Ball Prefab
Ball Prefab

トップに戻る

PhysxBallスクリプト

ボールがPhysX主導であり、NetworkRigidbodyがネットワークデータを考慮するので、処理する特別なコードの必要が親戚にあたるキネマティックより少なくなります。PhysxBall.cs に追加する必要があるのは、数秒経った後にボールをデスポーンするタイマー(キネマティックなボールと完全に同様)と、初期前進速度を設定するメソッドだけです。

これらは両方ともInit()メソッドでカバーされます。以下を参照してください。:

using UnityEngine;
using Fusion;

public class PhysxBall : NetworkBehaviour
{
  [Networked] private TickTimer life { get; set; }

  public void Init(Vector3 forward)
  {
    life = TickTimer.CreateFromSeconds(Runner, 5.0f);
    GetComponent<Rigidbody>().velocity = forward;
  }

  public override void FixedUpdateNetwork()
  {
    if(life.Expired(Runner))
      Runner.Despawn(Object);
  }
}

トップに戻る

インプット

ボールをスポーンするには、キネマティックボールの場合と同じ3ステップに従ってコードを拡張する必要がありますが、代わりに第2のマウスボタンを使用するように変更しています。以下で見ていきましょう。

1. NetworkInputData

NetworkInputData.csで新しいボタンフラグを追加する:

using Fusion;
using UnityEngine;

public struct NetworkInputData : INetworkInput
{
  public const byte MOUSEBUTTON1 = 0x01;
  public const byte MOUSEBUTTON2 = 0x02;

  public byte buttons;
  public Vector3 direction;
}

トップに戻る

2. BasicSpawner

BasicSpawner.csで、初めと同じ方法で第2のマウスボタンをポーリングし、以下の様にフラグを設定する:

  private bool _mouseButton0;
  private bool _mouseButton1;
  private void Update()
  {
    _mouseButton0 = _mouseButton0 || Input.GetMouseButton(0);
    _mouseButton1 = _mouseButton1 || Input.GetMouseButton(1);
  }

  public void OnInput(NetworkRunner runner, NetworkInput input)
  {
    var data = new NetworkInputData();

    ...

    if (_mouseButton1)
      data.buttons |= NetworkInputData.MOUSEBUTTON2;
    _mouseButton1 = false;

    input.Set(data);
  }

トップに戻る

3. Player

Player.csは、実際にボール振れハブをスポーンするコードを保持するため、以下のプレハブリファレンスに加えて、

[SerializeField] private PhysxBall _prefabPhysxBall;

Playerはスポーンを呼び出して、前に作成しておいたInit()メソッドを使用して速度(前回の前進方向に乗算した定数)を設定する必要がある  

public override void FixedUpdateNetwork()
{
  if (GetInput(out NetworkInputData data))
  {
    data.direction.Normalize();
    _cc.Move(5*data.direction*Runner.DeltaTime);

    if (data.direction.sqrMagnitude > 0)
      _forward = data.direction;

    if (delay.ExpiredOrNotRunning(Runner))
    {
      if ((data.buttons & NetworkInputData.MOUSEBUTTON1) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabBall,
          transform.position+_forward,
          Quaternion.LookRotation(_forward),
          Object.InputAuthority,
          (runner, o) =>
          {
            // Initialize the Ball before synchronizing it
            o.GetComponent<Ball>().Init();
          });
      }
      else if ((data.buttons & NetworkInputData.MOUSEBUTTON2) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabPhysxBall,
          transform.position+_forward,
          Quaternion.LookRotation(_forward),           
          Object.InputAuthority,
          (runner, o) =>
          {
            o.GetComponent<PhysxBall>().Init( 10*_forward );
          });
      }
    }
  }
}

最後に、新しいボールのテストのため、作成したプレハブをPlayerプレハブのPrefab Physx Ballフィールドに割り当て、ビルドして実行します。

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