Pre-built Components
はじめに
Fusionでは、すぐに使えるように様々なNetworkBehaviour
が用意されています。
NetworkRunner
NetworkRunner
は、Fusionの中核をなすものです。NetworkRunner
は、ネットワークへの接続を管理し、入力の収集からスナップショットのマージ、コールバックやSimulationBehaviour
のライフサイクルメソッドの呼び出しまで、シミュレーションを制御します。 シーン内のNetworkRunner
は、クライアントとサーバーのそれぞれに1つだけ存在します。
これらのタスクを実行するために、NetworkRunner
はすべてのNetworkObject
、NetworkBehaviour
、SimulationBehaviour
を追跡します。
プロパティ
すべての NetworkBehaviour
は Runner
プロパティを介して現在の NetworkRunner
にアクセスでき、Runner 自体もいくつかの重要なシステムプロパティを公開しています。
IsServer
: このランナーが権威あるサーバーを表している場合はtrue。Stage
: シミュレーションの現在のステージです。シミュレーションが次の状態を予測している場合にはForward
、サーバーのアップデートに合わせて古い状態を再シミュレーションしている場合にはResimulate
になります。なお、Resimulate
はサーバー上や、シミュレーションが常にForward
であるClient-Authorityモードでは発生しません。
GameMode
GameMode
は、ローカルのピアがどのように動作するかを定義します。GameMode
は、NetworkRunner.StartGame()
メソッドのパラメータとして渡されます。
client
: クライアントとして動作し、ローカルプレイヤーを作成して、クライアントホスト(クラウド共有)または専用ホスト(サーバーベース)に接続します。host
: サーバーとして動作し、ローカルプレイヤーを作成します (サーバー + クライアント)server
: 専用のサーバーとして動作し、プレイヤーはいません。shared
: クライアントとして動作し、ローカルプレイヤーを作成してFusion Plugin Serverに接続します。single
: "サーバー "として動作し、ローカルプレイヤーを作成します。
NetworkTransform
NetworkTransform
は、オブジェクトの実際のローカルなTransform
と、そのシミュレーションされた状態を補間することで、単純な運動オブジェクトを管理します。
NetworkRigidbody
リジッドボディの場合、NetworkRigidbody
は単に古い状態を補間するだけでなく、物理オブジェクトの予測可能な性質を利用して、より正確なローカル位置を推定します。
NetworkMecanimAnimator
NetworkMecanimAnimator
は、関連する Unity mechanim Animator
コンポーネントが持つパラメータの状態や値を同期させます。
Unity の Animator
コンポーネントは巻き戻しや再シミュレーションができないため(前方にのみ動作するように設計されています)、ティックの状態を正確に設定することができないため、ティック精度のアニメーションに依存できないことに注意する必要があります。
この前方にのみ動作する制限のため、NetworkMecanimAnimator
は再シミュレーションを試みず、NetworkMecanimAnimator
は Animator
コンポーネントを State Authority から Proxies に同期させるだけです。また、入力機関はForward tickでAnimatorに変更を適用する必要があります。
C#
void FixedUpdateNetwork()
{
// Only apply changes to the Animator if input is available
// (which is true for StateAuthority and InputAuthority),
// and only on Forward ticks (resimulation should be ignored).
if (GetInput(out var input) && Runner.IsForward)
{
// Apply inputs to Animator
}
}
SetTrigger()
パススルーの NetworkMecanimAnimator.SetTrigger()
メソッドは Animator.SetTrigger()
コールの代わりに使用すべきです。トリガーは一時的で、 NetworkMecanimAnimator
が Animator
コンポーネントの値を取得する前にバックブールを false にリセットすることが可能なためです。また、便利なことに NetworkMecanimAnimator.SetTrigger()
には passThroughOnInputAuthority
オプションがあり、入力権限ですぐに Animator.SetTrigger()
にパススルーすることができます。
NetworkCharacterControllerPrototype
このコンポーネントはプロトタイピングのサンプルで、Unity の CharacterController
を NetworkObject
に同期させる方法を示しています。Unity の CharacterController
は本質的に予測や再シミュレーションと互換性がないので、このプロトタイプは適切なタイミングで CC を有効にしたり無効にしたりしてその制限を回避する方法を示します。このコンポーネントは基本クラスとして使用し、必要に応じて拡張することができます。また、独自のカスタム実装の出発点としてコピーして名前を変更することも可能です。
NetworkCharacterController (廃止予定)
最も不安定なオブジェクトは、プレイヤーが直接操作するもので、一般的にCharacter Controllerと呼ばれています。Fusionには、このような特殊なケースに対応するために NetworkCharacterController
があります。
ビルド済みの NetworkCharacterController
は、一般的に望まれる動作を備えているので、素早くプロトタイプを作成することができます。しかし、キャラクタコントローラの実装は非常にゲームに依存するため、万能なキャラクタコントローラは存在しません。
そのため、NetworkCharacterController
が使用する2つのコアメソッド Move()
と ComputeRawMovement()
のソースコードに目を通し、ゲーム制作のための代替カスタムキャラクタコントローラを作るためのインスピレーションを得ておくことをお勧めします。
ComputeRawSteer()
ComputeRawSteer()
は内部メソッドで、キャラクターが現在行っている動きの種類に基づいて、動きの計算の大部分を行います。ビルド済みの NetworkCharacterController
では、Move()
が ComputeRawMovement()
から movementPack
の値を要求する際に、構造体への参照を渡して値を埋めています。
C#
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()
関数の基本的な実装です。動作のクエリを実行し、その結果を使って新しいVelocityを計算し、トランスフォームポジションに進入の補正とVelocityの統合を適用します。Rotationは変更しません。
direction
: 意図された移動方向で、移動クエリと加速の対象となります。callback
: 任意のカスタムコールバックオブジェクトです。layerMask
: 任意のレイヤーマスクです。渡さない場合は、コンフィグのデフォルトが使用されます。
C#
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のメカニムAnimator
が持つパラメータの値を同期させます。
注意: アニメーション自体を同期させるわけではありません。
NetworkEvents
NetworkEvents
は、NetworkRunner.AddCallbacks()
の代わりに使用して、Unityインスペクタで直接イベントハンドラを配線することができます。コンポーネントを NetworkObject
に追加し、ドラッグ&ドロップで個々のイベントハンドラを登録するだけです。
これは、ネットワークイベントをUnityシーンから設定する必要があるまれなケースの便宜のために含まれています。
Back to top