character movement コンポーネント は アクタ コンポーネント です。歩行、落下、水泳、飛行など共通の移動モードで、ヒューマノイド キャラクター に対するカプセル化された移動システムを提供します。Character movement コンポーネントにはネットワーク ゲームプレイ向けの堅固な統合機能が用意されています。移動モードはすべてデフォルトでレプリケートするように構築され、開発者がネットワークでの移動をカスタムで作成できるフレームワークが用意されています。
Character Movement の基本
UCharacterMovementComponent
は ACharacter
アクタ クラスとそこから派生する ブループリント に事前にアタッチされます。
TickComponent
関数の間に、UCharacterMovementComponent
は PerformMovement
を呼び出し、現在使用している 移動モード の種類とプレイヤーの入力変数に基づいて、ワールド内で期待される加速度を算出します。プレイヤーの入力変数は通常 APlayerController
の control input 変数で表されます。移動計算が終了したら、UCharacterMovementComponent
は最終的な移動を、所有するキャラクターに適用します。移動計算が最終的に確定すると、UCharacterMovementComponent
は最終的な移動を所有するキャラクターに適用します。
ACharacter
は APawn
から派生していますが、キャラクターは、単にポーンに character movement コンポーネントが追加されたものではありません。 UCharacterMovementComponent
と ACharacter
は同時に使用するように設計されており、 ACharacter
は、特に UCharacterMovementComponent
でのレプリケーションを簡単にするために、複数のレプリケートされた変数と関数をオーバーライドします。
PerformMovement と移動物理
PerformMovement
関数は、ゲームワールドでキャラクターを物理的に移動する役割を担当します。ネットワークを利用しないゲームでは、UCharacterMovementComponent
は各ティックで直接 PerformMovement
を呼び出します。ネットワーク ゲームでは、PerformMovement
はサーバーとクライアントの特別な関数で呼び出され、プレイヤーのローカル マシンで最初の移動を実行するか、またはリモート マシンでその移動を再現します。
PerformMovement
は以下の処理を実行します。
- 衝撃、力、重力など外部からの物理的影響を適用する。
- アニメーション ルート モーションと root motion sources から移動を計算する。
StartNewPhysics
を呼び出す。これはキャラクターが使用する移動モードの種類に基づいて、Phys*
関数を選択する。
各移動モードには、専用の Phys*
関数があり、速度と加速度を算出します。例えば、PhysWalking
は地上を移動しているときのキャラクターの移動に関する物理運動を決定します。一方 PhysFalling
は空中での振る舞いを決定します。これらのビヘイビアの特性をデバッグする場合、これら各関数の内容を確認することができます。
移動モードがティックの間に変わる場合、例えば、キャラクターが落下を始める、またはオブジェクトに衝突するとき、Phys*
関数が StartNewPhysics
を再び呼び出し、新しい移動モードでキャラクターの移動を続けます。 StartNewPhysics
と Phys*
関数はそれぞれ、発生した StartNewPhysics
のイテレーション回数だけ実行されます。パラメータ MaxSimulationIterations
はこの反復が許される最大回数を示します。
動きのレプリケーションの概要
UCharacterMovementComponent
はオーナーの ネットワーク ロール を使用して、移動のレプリケート方法を決定します。次のとおり、3 種類のネットワーク ロールがあります。
ネットワーク ロール | 説明 |
---|---|
Autonomous Proxy | キャラクターはその 所有クライアントの マシンにあり、プレイヤーによりローカルでコントロールされます。 |
Authority | キャラクターはゲームをホストするサーバーに存在します。 |
Simulated Proxy | コントロールしているのがサーバーの AI であるか、異なるクライアントの自動プロキシであるかに関わらず、リモートでコントロールされるキャラクターはそれが表示されるどのクライアントにも存在します。 |
レプリケーション プロセスは TickComponent
関数内のサイクルに従います。これはティックごとにそれ自体を繰り返します。ネットワーク ゲームでキャラクターの移動を実行するとき、ローカル以外のマシンにあるコピーは、互いに Remote Procedure Calls (RPC) を実行し、異なるネットワーク ロールで、必要に応じて異なる実行パスを使用し、移動情報を同期します。
次の表では、このプロセスの間に各マシンで UCharacterMovementComponent
が実行することの概要をステップごとに示します。
段階 | 説明 |
---|---|
Autonomous Proxy (自動プロキシ:所有するプレイヤーのクライアント) | |
1 | 所有しているクライアントが自動プロキシをローカルでコントロールします。 PerformMovement は移動コンポーネントに対して移動の物理ロジックを実行します。 |
2 | このプロキシは、今どのように移動したかに関するデータを含む FSavedMove_Character を構築し、それを SavedMoves のキューに入れます。 |
3 | 同様の FSavedMove エントリが統合されます。自動プロキシはそれらの凝縮したデータをサーバーに ServerMove RPC で送信します。 |
Authoritative Actor (権限のあるアクタ:サーバー) | |
4 | サーバーは ServerMove を受け取り、PerformMovement を使用してクライアントの移動を再現します。 |
5 | ServerMove の後に位置が、クライアントがレポートする最終位置に一致するかどうかを確認します。 |
6 | サーバーとクライアントの最終位置が一致すると、クライアントに移動が有効だったというシグナルを送信します。一致しない場合、ClientAdjustPosition RPC で修正を送信します。 |
7 | サーバーは ReplicatedMovement 構造体をレプリケートして、位置、回転、現在の状態を、接続された他のクライアントにあるシミュレートされたプロキシに送信します。 |
Autonomous Proxy (自動プロキシ:所有するプレイヤーのクライアント) | |
8 | クライアントは ClientAdjustPosition を受け取ると、サーバーでの移動を再現し、SavedMoves キューを使用して、ステップを再トレースして、新しい最終位置を取得します。移動が正常に解決されると、保存された移動はキューから削除されます。 |
Simulated Proxy (シミュレートされたプロキシ:他のすべてのクライアント) | |
9 | シミュレートされたプロキシはレプリケートされた移動情報を直接適用します。ネットワーク スムージング により最終的な動きに対してビジュアルがクリーンアップされます。 |
このプロセスは、ネットワーク ゲーム内で 3 種類のマシンすべてで移動を同期します。対象のキャラクターをコントロールするユーザーに対して、サーバーからの干渉を最小限に抑え、キャラクターをローカルにコントロールしているという感覚を維持する必要があります。さらに他のユーザーのキャラクターが、それぞれのマシンで行っている移動がほぼそのままの状態で確認できる必要があります。
このプロセスの複雑さの大半は、プレイヤーが自分のキャラクターを可能な限りストレスなく操作できるように、自動プロキシとそのサーバー上の対応物との間で予測と修正を調整する点に集約しています。一方、シミュレートされたプロキシで必要なのは、サーバーが指定する対象のあるべき場所を更新することだけです。
レプリケートされたキャラクター移動の詳細
次のセクションでは、前に概要を示したプロセスをステップごとに詳しく説明します。多くのプロジェクトでは UCharacterMovementComponent
のビヘイビアをオーバーライドすることは想定されていませんが、同様の機能を開発する、または変更する場所を知る必要がある場合に参照として使用できます。
このセクションでは、キャラクターの通常移動モードをレプリケートする点に注目します。ただし、ルート モーションと別のアクタに基づく移動には代替実行パスがあります。これはこのセクションでリストされているステップと同様のものに従います。
所有クライアントでのローカルの移動
自動プロキシは TickComponent
でローカルに移動を処理し、記録してから、サーバーの権限でもって再現され適用されるようにサーバーに送信します。このセクションでは、自動プロキシで各ティックに実行されるプロセスに分けて説明します。
クライアント予測データを作成する
自動プロキシは、移動の記録とサーバーからの修正情報の処理を扱う一環として、FNetworkPredictionData_Client_Character
オブジェクトを ClientPredictionData
という名前で構築します。以下のパラメータがあります。
- タイムスタンプ (クライアントがサーバーと通信したときを基点)
- 保存または中断された移動のリスト
- サーバーの修正をもとに保存された情報
- 修正の適用方法を示すフラグ
- ビヘイビアのスムージングを決定する各パラメータ
ClientPredictionData
にはこれらのパラメータとやり取りするユーティリティ関数も含まれます。このオブジェクトの情報と関数の完全なリストは「FNetworkPredictionData_Client_Character
の API リファレンス」にあります。これらのパラメータは、クライアントがローカルの移動を実行し、サーバーに送信する移動を準備し、修正を処理するときに、頻繁に参照と変更が行われます。
サーバー修正を再現する
プレイヤーの入力やワールド内の物理的作用を処理する前に、自動プロキシは ClientUpdatePositionAfterServerUpdate
を呼び出します。これはサーバーが何らかの修正を、所有するプレイヤーに送信したかどうかをチェックします。送信した場合は、ClientPredictionData
内の変数 bUpdatePosition
は true であり、キャラクターはクライアント修正プロセスを通じて、サーバーから送信された移動をすべて再現します。サーバーでの修正の詳細については、「クライアントの誤差と修正を処理する」セクションを参照してください。
移動を実行し記録する
自動プロキシのキャラクターでは ReplicateMoveToServer
を TickComponent
の途中で呼び出します。PerformMovement
を直接呼び出すことはしません。この関数は、キャラクターが移動を行い、それをサーバーに送信するときに移動の記録を行うために必要なロジックを PerformMovement
に加えたものです。FSavedMove_Character
構造体は自動プロキシが各ティックの間に移動を開始し終了する方法を記録するもので、その後に、ServerMove RPC でサーバーに送信されるデータの最小サブセットが入ります。以下のパラメータがあります。
- キャラクターの最終位置と回転に関する情報
- キャプチャされた移動の入力の内容
- キャラクターが保持するベロシティと加速度の内容
- アニメーション モンタージュ からキャプチャされるルート モーションの情報
この構造体のパラメータの完全なリストは API reference for FSavedMove_Character
を参照してください。この情報によりサーバーは、プレイヤーが実行した移動を再現し、クライアントの最終位置をチェックできます。
PerformMovement
を処理した後、ReplicateMoveToServer
関数は、キャラクターの移動の結果をクライアント予測データ (FSavedMove_Character
構造体の NewMove
という名前) に記録します。それから SavedMoves
というバッファに追加されます。このバッファでは前に保存された移動から最新の移動の順に並んでいて、保存された移動がサーバーに送信されるまでキューとして働きます。バッファにある類似した移動は、帯域を圧迫しないために送信前に、単一の FSavedMove_Character
にまとめられます。パラメータ PendingMove
は、後続の移動に統合するために待機している移動のためのストレージとして機能します。
これらは受信確認 ( ACK ) したときにバッファから削除されます。サーバーはクライアントの位置が有効であることを確認することにより、直接移動を ACK できます。あるいはクライアントはサーバーからの修正を処理したときに、移動を ACK できます。ACK された最終の移動は今後に修正を処理するときに使用するため LastAckedMove
に保存されます。
移動をサーバーに送信する
ReplicateMoveToServer
は関数 CallServerMove
を実行することにより終了します。この関数は、サーバーで ACK されていない、キューにある一番新しい移動と一番古い移動を取り込みます。これはサーバーに移動を送信するための最終準備を実行し、適用可能な場合に、古い移動を最初に送信することを試み、それから新しい移動に対するファイナライズした移動を送信するために適切な ServerMove 関数を呼び出します。最終の ServerMove は直接 UCharacterMovementComponent
の所有キャラクターに 信頼できない サーバー RPC として送信されます。
ServerMove 関数が「信頼できない」であるのには以下の 2 つの理由があります。
- 通常のゲームプレイでは、ServerMove 関数が頻繁に呼び出されるため、「信頼できる」に設定されていると、「信頼できる」関数のためにバッファがオーバーフローして、所有プレイヤーの接続が強制的に切断されます。
- 保存された移動のバッファリングシステムでは、途中で移動の情報が失われたら再送信し評価することが保証されています。これは「信頼できる」関数と類似したセーフティ ネットを提供しますが、「信頼できる」RPC バッファがオーバーフローするリスクはなく、また古すぎる移動データを確実に破棄するルールが加えられています。
サーバー上で移動を評価する
サーバーは移動をゲームのティック サイクルに同期して、定期的にティックを実行することはありません。代わりに、ServerMove 呼び出しを自動プロキシから受け取るまで待機し、ServerMove_Implementation
はサーバー側で移動を処理し、クライアントの移動を再構築し、不一致がないかどうかをチェックします。このセクションでは ServerMove が実行するプロセスを詳しくステップごとに示します。
このドキュメントでは ServerMove
と ServerMove_Implementation
について大まかに触れていますが、ServerMove 呼び出しには、キューに格納されている情報の種類に基づいて複数のタイプがあります。
サーバー予測データを作成する
character movement コンポーネントの権限バージョンは FNetworkPredictionData_Server_Character
オブジェクトを ServerPredictionData
という名前で作成します。これはキャラクターが存続する間存在します。ServerMove_Implementation
の間、このオブジェクトは所有するクライアントの移動を再現するために、後で各プロセスによって使用される情報を格納します。サーバーがデータを受け取ると、このオブジェクトはバックグラウンドで継続的に変更されます。データのパラメータには以下があります。
- タイムスタンプ (サーバーのデルタ時間を計算するために使用)
- 中断したクライアント調整
- 時間の不一致の解決に関するフラグ
- サーバーが ACK する、または移動を修正するかどうかを示すフラグ
パラメータの情報と関数の完全なリストは API reference guide for FNetworkPredictionData_Server_Character
を参照してください。
クライアント タイムスタンプを検証する
ServerMove RPC で送信される情報には、移動が発生したときのタイムスタンプが含まれます。サーバーのタイムスタンプとクライアントのタイムスタンプの不一致が非常に大きい場合、クライアントのタイムスタンプが失効したとみなし、移動は破棄されます。不一致が大きくない場合、解決するようにフラグが付けられ、UCharacterMovementComponent
が ProcessClientTimeStampForTimeDiscrepancy
を使用し、次のステップでデルタ時間に対するオーバーライドを作成します。
デルタ時間を計算する
一般にデルタ時間は現在のティックと前のティックとの間で経過した時間から取得されますが、サーバーにあるキャラクターは移動を計算するために TickComponent
を使用しません。代わりに、ServerMove_Implementation
は GetServerMoveDeltaTime
を呼び出して、ServerMoves を受け付けるときに移動を計算します。タイムスタンプの不一致を解決しようとするとき、サーバー予測データにフラグが付いている場合、TimeDiscrepancyResolutionMoveDeltaOverride
を使用します。時間の不一致がない場合、サーバー予測データを使用して、現在の ServerMove RPC のタイムスタンプと最後の ServerMove RPC のタイムスタンプの差を利用して、デルタ時間を算出します。セキュリティの追加レイヤーを提供するために、これらの計算の大部分が、クライアントではなく、サーバーのタイムスタンプで実行されます。これによりローカルのゲーム クロックをスピードアップして、全体のスピードをいじるというハッキング手法を防止します。
移動を評価する
サーバーは ServerMove RPC からのデータを使用して、所有するプレイヤーのコントローラーの回転を再構築してから、関数 MoveAutonomous
を呼び出し、キャラクターの加速度、回転、ジャンプ入力を処理します。
MoveAutonomous
は PerformMovement
関数を使用し、前のステップで得られた、この再構築されたデータとデルタ時間を使用して、キャラクター移動の物理運動をシミュレートします。クライアントで開始した場所から移動をシミュレートするのではなく、サーバーは ServerMove が呼び出されたとき、キャラクターの独自コピーがある場所からシミュレートします。
キャラクターがアニメーションからルート モーションを実行している場合、MoveAutonomous も、指定されたデルタ時間でキャラクターのアニメーション ポーズをティックします。アニメーション イベントはどれも適切にトリガーされます。他の場合、アニメーションは普通にティックされます。
クライアントの誤差と修正を処理する
サーバーでの移動は、サーバーと所有するクライアントが同じ場所で移動を開始するという前提で機能し、クライアントがレポートする移動をサーバーがそのまま実行する場合は、移動を終了する位置も、同じです。接続の問題のため、クライアントでの移動が破棄される場合、またはクライアントが不正なデータを送信した場合、2 つが異なる場所で終了し、修正が必要になります。関数 ServerMoveHandleClientError
がこれらの処理に対応します。
調整が必要な場合を判定する
修正を頻繁に発行すると、帯域に影響を及ぼし、クライアントは保存された大量の移動を何度もシミュレートし直すことになります。そのため、WithinUpdateDelayBounds
から返された値をまずチェックして、移動の間で最小時間が経過しているかどうかを確認します。false
が返る場合、修正は発行されません。true が返る場合、残りの処理の実行が許可されます。
次に、ServerCheckClientError
を使用して、修正が必要なほど、サーバーとクライアント間の誤差が大きいのかどうかを確認します。true が返る場合、または bForceClientUpdate
に true が設定されて、修正が強制される場合、ServerMoveHandleClientError
では引き続き残りの処理が実行されます。
これらの両方の処理を調整するパラメータは BaseGame.ini
にあり、プロジェクトの DefaultGame.ini
でプロジェクト固有の値をオーバーライドできます。値 ClientErrorUpdateRateLimit
は、サーバーからクライアントに送信する誤差修正の最小遅延 (秒単位) を示します。値 MAXPOSITIONERRORSQUARED
は、修正前のネットワーク プレイで受け付けられた位置誤差の 2 乗値です。これらの両方がコンフィグ ファイルの [/Script/Engine.GameNetworkManager]
セクションにあります。
調整が必要な場合、PendingAdjustment
という名前の FClientAdjustment
構造体にサーバー予測データが格納されます。これはサーバーのキャラクターのコピーからサンプルされた、現在の移動の変数です。これには位置、回転、速度、またキャラクターの移動に対するベースとして機能するあらゆるオブジェクトが含まれます。不要な場合、PendingAdjustment
の bAckGoodMove
値を true
に設定して、クライアントの移動に有効フラグを付けます。
クライアント調整を送信する、または移動を ACK する
クライアントに対する受信確認された移動に対する最終呼び出しは、SendClientAdjustment
で行われます。この関数は、ServerMove_Implementation
の一部として実行されるのではありません。むしろ、これは UNetDriver::ServerReplicateActors
の一部で、サーバーのティックの最後に呼び出されます。これは同様に、他のクライアント調整 RPC 呼び出しを担当します。SendClientAdjustment
が呼び出されると、前のステップで構築した予測データにどのようにフラグがついているのかに基づいて動作します。
サーバー予測データの PendingAdjustment
で bAckGoodMove
に true
のフラグが付いている場合、ClientAckGoodMove
RPC を呼び出し、移動を ACK します。これにより、移動が有効であったことが、所有するクライアントのマシンの自動プロキシに通知されます。これは、所有するクライアントの側で SavedMoves
バッファから元の移動を削除し、将来の予測データを構築するときに使用するため LastAckedMove
として記録します。
PendingAdjustment
で bAckGoodMove
に false のフラグが付いている場合、クライアント調整関数を呼び出し、最終修正をクライアントに送信します。
自動プロキシでクライアント調整を受信する
クライアント調整 RPC には、ClientAdjustPosition
、ClientAdjustRotation
、速度がゼロであるときに発生する簡略バージョン、そしてルート モーションベースの移動で特に使用されるそれらのバージョンがあります。サーバーはこれらの複数を SendClientAdjustment
の一部として呼び出すことがありますが、これは必要な修正内容の性質や重大度によって変わります。必要な修正が適用されると、これらのそれぞれは ClientPredictionData
に移動の ACK を通知でき、それぞれで bUpdatePosition
に true のフラグが付きます。
その後、最終的な修正が、クライアントの次の TickComponent
の先頭に ClientUpdatePosition
を使用して適用されます。
シミュレートされたプロキシに移動をプリケートする
オーナー以外のクライアント マシンにあるキャラクターは、自動プロキシではなく、シミュレートされたプロキシです。サーバーから受け取った移動のデータをシミュレートされたプロキシにレプリケーションするプロセスは、非常に単純です。シミュレートされたプロキシの唯一のジョブがサーバーに応答することだからです。移動を物理的にシミュレートするのではなく、サーバーから移動のアップデート情報を受け取ると、サーバーが送ってきたとおりの位置、回転、速度に設定し、さらにいくつかのプロセスを追加して、動きを滑らかでそれらしいものにします。
レプリケートされた移動の情報を格納する
アクタが移動をレプリケートするとき、そのトランスフォームを直接レプリケートすることはしません。代わりに、すべてのアクタは、レプリケートされた変数を ReplicatedMovement
という名前で維持します。これには構造体 FRepMovement
を使用します。
ブールの bReplicateMovement
は、ブループリントの Replicate Movement 変数で表され、アクタにフラグを付けて、この構造体に移動の情報を格納し、それをクライアントにレプリケートします。クライアントが ReplicatedMovement
に対するアップデートを受け取ったとき、RepNotify 関数 OnRep_ReplicatedMovement
は格納された移動のデータをアンパックし、アクタの位置と速度に対してアップデートを適切に実行します。
ReplicatedMovement
またはその OnRep はブループリント内部からアクセスできませんが、OnRep_ReplicatedMovement
は C++ でオーバーライドでき、ReplicatedMovement
のレプリケーション条件も GetLifetimeReplicatedProps
でオーバーライドできます。これにより、移動のレプリケーションが C++ ベースのアクタ クラスでどのようにふるまうのかをカスタマイズできます。
ACharacter
では、ReplicatedMovement
構造体はシミュレートされたプロキシに対してのみレプリケートされます。自動プロキシでは無視されます。この場合には、サーバーの移動とクライアントの調整 RPC を使用して移動を処理します。
キャラクターがベースとして別のアクタを使用している場合、代わりに、ReplicatedBasedMovement
を使用します。これは、追加のロジックを適用して、クライアントがサーバーに従って、必ず正しいベースになるようにします。キャラクターがルート モーション システムを使用する場合、RepRootMotion
の使用が優先され、これらのすべてのプロセスは 無視されます。
シミュレートされたプロキシで移動をティックする
UCharacterMovementComponent
がシミュレートされたプロキシで TickComponent
を実行するとき、SimulatedTick
を呼び出して、移動をシミュレートするロジックを処理します。これは前述した、レプリケートされた移動を実行しません。代わりに、SimulatedTick
は直近に提供された、レプリケートされた移動のデータに従って、移動を続けます。標準的な物理移動を行う際には、SimulateMovement
関数を呼び出して、最終検証を実行し、SmoothClientPosition
でネットワーク スムージングを実行します。
シミュレートされた移動を実行する
SimulateMovement
関数がシミュレートされたプロキシ キャラクターの移動に対応します。さらに SimulatedTick
で呼び出されるのに加えて、OnRep_ReplicateMovement
でも呼び出されます。この関数は次のプロセスを実行します。
- 所有するキャラクターの
GetReplicatedMovement
関数を呼び出して、ReplicatedMovement
への参照を取得します。 - セーフティ チェックを実行し、レプリケートされた移動のデータが有効であり、クライアントのベースが解決されことを確認します。
- 何らかのネットワーク アップデートを受け取ったかどうかをチェックします。
GetReplicatedMovementMode
でサーバーから取得されたキャラクターの移動モードを適用します。- ネットワーク アップデートに関するすべてのフラグをリセットします。
- 現在の
MovementMode
とキャラクターの現在の状態に関する情報に基づいてシミュレートされた移動に対するロジックを実行します。
標準的な移動の物理ロジックと比較すると、シミュレートされた移動に対するロジックは非常に単純で、小さな関数群に分解するのではなく、SimulateMovement
関数自体にほとんどが含まれています。ただし、この関数にはキャラクターのローカル移動の状態を更新する役割もあり、それには移行先の移動モードの内容、キャラクターが地上に降りたかどうか、その速度はどれほどであるかなどが含まれます。この情報はキャラクターがそのアニメーションを正しく更新でき、その移動は満足いく程度に正確に見えることを保証します。
ネットワークのスムージング
キャラクターの位置と回転を単にコピーするだけで移動をレプリケートした場合、キャラクターは一瞬ごとにテレポートしているように見えます。これはローカル マシンのレンダリング レートがネットワークでデータを送信するレートよりも速いためです。クライアントは 240 Hz のリフレッシュ レートでモニタにレンダリングできますが、レプリケートされた移動を送信できるのは 30 Hz. 程度です。
ネットワーク スムージングはこの移動を円滑化するプロセスで、ターゲットに瞬間的に動かすのではなく、ソースの位置からターゲットの位置に補間しながらキャラクターを徐々に移動します。ソースの位置はキャラクターの現在の位置から得られ、ターゲットはクライアント予測データから与えられます。補間自体は SmoothClientPosition
で処理され、これは NetworkSmoothingMode
を使用し、使用する補間の種類を決定します。
特別な移動のケース
次のセクションでは特殊移動の一般的なケースに関する情報を示します。これには特殊能力で使用されるような、テレポーテーション、カスタム移動、コードによる移動があります。
マルチプレイヤーでキャラクターをテレポートする
SetLocation の各関数のいずれかや Teleport ブループリント ノードで呼び出すことによって、次のようにネットワーク ゲームでキャラクターをテレポートできます。以下の条件があります。
- 必ずサーバーで呼び出す。
SetLocation
関数を使用する場合、bTeleport
変数を true に設定し、移動がテレポートとして認識されるようにする。
これらの条件が満たされる場合、サーバーの予測データ、およびテレポートとしてレプリケートされた移動に、移動が記録され、すべてのクライアントが適切に応答して、スムージングを適用しないで、キャラクターを対象の位置に動かします。
カスタムの移動モードを使用する
移動モード MOVE_Custom
は他の移動の物理ロジックをすべて停止し、UCharacterMovementComponent
の通常のプロセスによる干渉なしで、カスタムの移動のロジックを実装できます。
UCharacterMovementComponent
は一般にブループリント化できず、ブループリントのカスタムの移動は一般に、UpdateCustomMovement イベントを使用してキャラクター内に直接実装されます。Custom Movement Mode バイト変数を使用して、サブモードを提供できます。スイッチオン整数またはカスタム列挙型への変換があります。
UpdateCustomMovement
は PhysCustom
関数 (UCharacterMovementComponent
内) により呼び出されます。関数 StartNewPhysics
、PhysCustom
および移動に関する他のすべての物理関数群は仮想関数で、C++ でカスタムの UCharacterMovementComponent
を作成する場合、それらを直接オーバーライドできます。
特殊なケースの移動をルート モーションでレプリケートする
ゲームプレイ アビリティ システム で作成した能力が有効な間、またはアニメーション主導のアクションの間のような短い期間、キャラクターの移動を直接コントロールする必要がある場合があります。ローカルのみのゲームでは、これは簡単に実行できますが、レプリケートされた特殊なケースの移動では、ルート モーションの使用が必要です。これは一般的にはアニメーションからの移動の適用を参照します。ルート モーション システムが、コードによる特殊なケースの移動にも適用されます。
ルート モーションは常に標準的な移動の物理ロジックに優先されます。UCharacterMovementComponent
が使用する移動モードの種類には関係ありません。ルート モーションが終了したとき、通常の移動が再開されます。
アニメーション モンタージュから操作する
ルート モーションのほとんどの適用は AnimMontages から生ずることが想定され、コード トリガーのワンショットのアニメーションに対して使用されます。ルート モーションの使用により、アニメーションが終了するまでキャラクターが実行する他の動きが停止されます。代わりにキャラクターは、スケルトンのルート ボーンからの移動を利用し、ワールド空間の移動に変換し、アニメーションでキャラクターを動かす方法をコントロールできます。これが完了すると、キャラクターは通常の物理ロジックに従って動くようになります。
キャラクターの移動モードが落下である場合、重力はキャラクターの Z 方向の移動に働き、キャラクターがルート モーションを実行するときでも当てはまります。
前述したレプリケーション プロセス内で、ルート モーション情報は FSavedMove_Character
構造体によりキャプチャされます。これには発生する元の AnimMontage、モンタージュ内のキャラクターの追跡位置、キャラクターの動き自体のパラメータが含まれます。
所有するクライアントでの自動プロキシとサーバーは、同じアニメーションを再生するかどうかをチェックしません。これは一般にコスメティック機能とみなされます。したがって、ゲームに接続されたすべてのマシンで AnimMontages が正しくトリガーされるようにゲームプレイ ロジックをプログラムする必要があります。ただし、シミュレートされたプロキシには、ルート モーションベースの移動を同期するため、前に概要を示したものに対する並列プロセスがあります。
Gameplay Ability System プラグインは、AnimMontages とルート モーションを、それらをトリガーする機能のレプリケートにより同期します。
ルート モーション ソースを使用する
場合により、特別のケースでキャラクターの位置を手動でコントロールする必要があります。例えば、キャラクターが指定の高さから空中に飛び出し、動くターゲットに着地する特殊能力を作成することがあります。
キャラクターを SetLocation
と SetRotation
により手動でコントロールすることは、スタンドアロン ゲームでは可能ですが、ネットワーク ゲームでは、この動きは前に示したレプリケーション プロセスでキャプチャされず、サーバーでクライアントの最終位置を誤差として認識し、修正を発行します。一方、アニメーション モンタージュからのルート モーションは、アニメーションから事前に計算された動きのみに従います。つまり、ルート モーションでは通常、他のキャラクターの位置など、リアルタイム情報をゲーム ワールドから取り込むことができず、ゲームプレイ変数を使用して簡単に微調整できません。
ルート モーション ソース はプログラマーがキャラクターのルート モーションを手動でコントロールする手段を提供します。これにより、キャラクターの動きをプログラムからコントロールでき、ネットワーキングの間にルート モーションを処理するため、前に示したシステムを活用します。
ルート モーション ソースは所有するクライアントの自動プロキシに適用する必要があります。
このシステムを使用するには、新しい FRootMotionSource 構造体を作成する必要があります。異なる FRootMotionSource バリアントは、異なる種類の移動に対して存在します。例えば、FRootMotionSource_MoveToForce は開始位置からターゲット位置への直線的な動きに使用されますが、一方 FRootMotionSource_JumpForce ではジャンプのような弧を描いて動きます。適切なルート モーション ソースを作成すると、期待されるソース位置、ターゲット位置、移動をどのように処理するのかを示すパラメータでプロパティを初期化できます。
関数 UCharacterMovementComponent::ApplyRootMotionSource
はルート モーション ソースをキャラクターに適用し、後で参照に使用できるハンドルを返します。ルート モーション ソース自体は移動を処理しません。代わりに、Character movement コンポーネントは、アニメーションの代わりに、提供された FRootMotionSource
のパラメータと一貫性がある動きを実行します。これは結局、SavedRootMotion
(FSavedMove_Character
構造体内) に追加され、FRootMotionSource
が自動プロキシに適用された場合に、レプリケーション サイクルでキャプチャされます。
移動が完了したとき、UCharacterMovementComponent::RemoveRootMotionSource
を呼び出して、ApplyRootMotionSource
から返されたハンドルを使用して、それを削除する必要があります。
Gameplay Ability System プラグインにはルート モーション ソースを活用する複数の能力タスクが含まれ、プログラムによる複雑なシーケンスの移動を能力に対して実行できます。基本サンプルは AbilityTask_ApplyRootMotionMoveToForce
で参照できます。
ネットワーク経由のキャラクター移動をカスタマイズする
Unreal Engine では、カスタム関数パラメータのレプリケートされたキャラクター移動のサポートが可能です。デベロッパーがこの機能を必要とせず、レガシー API を維持する場合は、 SUPPORT_DEPRECATED_CHARACTER_MOVEMENT_RPCS
をプロジェクトのビルド ファイルで「0」以外の値に定義し、コンソール変数 "p.NetUsePackedMovementRPCs" を 0 に設定できます。
Character Movement コンポーネントは FSavedMove_Character
構造体を使用してネットワーク経由でデータを送信します。システムは、ネットワーク経由の送信用に 1 つ以上の更新の移動データを単一の可変長のビット ストリームに統合します。古いデータと新しいデータを一緒にパッケージ化することにより、ServerMoveOld
RPC が ServerMove
の後に呼び出される際に起きる、古い (ただし、まだ重要な) データが間違って使われないものとして無視される可能性がある潜在的な順番の問題を回避します。内部的には、Character Movement コンポーネントは新しい CallServerMovePacked
関数を使用して複数の FSavedMove_Character
インスタンスを FCharacterNetworkMoveDataContainer
にシリアル化し、古い CallServerMove
の使用法を置き換えます。
保存した移動データを拡張する
新しいデータを追加するには、まず FSavedMove_Character
を拡張して Character Movement コンポーネントが必要とする情報をすべて含めます。次に、FCharacterNetworkMoveData
を拡張してネットワーク経由で送信するカスタム データを追加します。多くの場合、これは FSavedMove_Character
に追加されたデータが反映されます。また、FCharacterNetworkMoveDataContainer
も拡張してネットワーク送信用に FCharacterNetworkMoveData
をシリアル化し、受信時には逆シリアル化できるようにする必要もあります。セットアップが完了したら、システムを次のように設定します。
-
Character Movement コンポーネントを、
SetNetworkMoveDataContainer
関数を使用して作成したFCharacterNetworkMoveDataContainer
サブクラスを使用するように変更します。この最も簡単な方法は、FCharacterNetworkMoveDataContainer
のインスタンスを Character Movement コンポーネントの子クラスに追加し、コンストラクタでSetNetworkMoveDataContainer
を呼び出すことです。 -
FCharacterNetworkMoveDataContainer
ではFCharacterNetworkMoveData
の独自のインスタンスが必要なため、(通常はコンストラクタで)FCharacterNetworkMoveData
サブクラスのインスタンスに指定します。詳細と例については「ベース コンストラクタ」を参照してください。 -
FCharacterNetworkMoveData
の拡張バージョンでは、ClientFillNetworkMoveData
関数をオーバーライドして保存した移動からデータをコピーまたは計算します。Serialize
関数をオーバーライドし、FArchive
を使用してデータの読み書きを行います。これは RPC が必要とするビット ストリームです。
サーバー応答をクライアントに拡張して、良好な移動を確認したり修正データを送信したりできます。そのためには FCharacterMoveResponseData
と FCharacterMoveResponseDataContainer
を拡張し、Character Movement コンポーネント バージョンの SetMoveResponseDataContainer
をオーバーライドします。
拡張した移動データにアクセスする
下位互換性を維持するために、サーバー上でクライアントの移動を処理し、修正を受け取った後でクライアント上でそれらを再生する関数スタックに変更を加えることはありません。これによりレガシー関数に対して安定した API が提供されますが、これは同時に、それらの関数のシグネチャが新しい移動データに対応しないことも意味します。移動の処理中にサーバー上のこのデータにアクセスしたり、再生中にクライアント上のこのデータにアクセスするには、GetCurrentMoveData
を呼び出して返された FCharacterNetworkMoveData
をサブクラスにキャストします。