RPG Movementデモ
このデモではPhotonを使ってキャラクターの基本的な動作を同期します。新しいPhotonTransformView
コンポーネントから様々なオプションを指定してリモートキャラクターの動作をローカルと変わらない程スムーズにします。
このデモではアニメーション特有のデータを送らずにアニメーションを同期させる方法についても説明しています。Animatorは動作の変化に反応します。動作は同期されるので適切なアニメーションを再生することができます。
このデモのキャラクターはプレハブ「Robot Kyle Mecanim」です。PUNのコンポーネントや、キャラクタにユーザ入力を適用するIdleRunJumpスクリプトが含まれています。
MecanimデモではPhotonAnimatorView
を使ってアニメーションデータを送信します。
The PhotonTransformView
ゲームオブジェクトにはPhotonTransformView
を追加することができます。これにはPhotonView
も含まれています。PhotonTransformView
を追加した後、それをPhotonView
のObserved Componentsリストに追加してください。(リストの下の+をクリックして新しいフィールドにPhotonTransformView
をドラッグ&ドロップしてください)
PhotonTransformView
コンポーネントには位置、回転、スケールの同期を有効または無効にするための3つのチェックボックスがあります。これらの同期を有効にすると、さらにオプションが表示されてデータの同期方法に関する詳細設定ができます。
これらのオプションがどのようにスムーズなネットワーク体験を可能にするかを説明します。
位置の同期
ゲームは位置の更新に最も左右されるのでオプションの種類も一番豊富です。
位置の更新は他と同様、1秒に10回送られます。100フレーム/秒のゲームの場合、リモートプレイヤーは10フレーム毎に更新されます。場合によっては更新が遅れたり欠損することがあります。
このような現象に対応してリモートオブジェクトの動きをローカルと同じようにスムーズにするため、次のような手法を使います:
- Interpolation(補間): 全てのフレームの位置データを送ることはできないので、他のクライアントから受信するデータは決してスムーズではありません。 Interpolationはキャラクタが各更新の間スムーズに動くよう配慮します。リモートオブジェクトが最新の位置にテレポートのように移動するのではなく、数フレームをかけてその位置に向かって動きます。
- Extrapolation(補外): Extrapolationは同期したキャラクタが現在どこにいるべきかを過去に受信したデータから推定します。更新が遅れたり欠損した場合、動きの乱れを改善できる場合はありますが、あくまでも推定です。修正が必要かもしれませんし、ゲームの種類によって異なります。
ゲームの種類によって適切なInterpolationやExtrapolationのオプションは異なります。 いくつかの設定を試してみてください。
Interpolateのオプション
Disabled:(無効): Interpolationが適用されません。新しい位置の更新が届いたら即時にGameObjectに適用されます。
FixedSpeed(一定速度): 新しい位置の更新が届くと一時的な変数に保管され、一定の速度でキャラクタがそこに向かって動きます。同期されたオブジェクトの速度が分かっている場合、このオプションを使うことによって動きをスムーズにできます。実際の速度が変化している場合、またはMoveTowardsのSpeed値がオブジェクトの実際の移動速度と異なる場合は動きに乱れがでます。
EstimatedSpeed(推定速度): 最後に更新された位置に向かってキャラクタがスムーズに移動します。このモードでは最後の位置と最新の位置の差からオブジェクトの速度を推定します。乗り物のようにゆっくり速度が変化するオブジェクトに最適です。
SynchronizeValues(値の同期): このモードでは元のオブジェクトが各更新時に実際の速度を送り、interpolationに適用します。随意で左右に動けるジャンプ&ランのように、キャラクタが急な速度変更を行う場合に最適です。しかしこのモードは動作速度と回転速度も同期されるので、送るデータ量が増えます。GameObjectのスクリプトが
SetSynchronizedValues(Vector3 speed, float turnSpeed)
を呼んでランタイムの速度や回転速度を修正したり、同期された値の更新を行います。多くの場合、動作スクリプトはGameObjectが動く速度を認識しているので、このモードで最もスムーズな結果を得られます。Lerp: MoveTowardsWithFixedSpeedと似ていますがMoveTowards関数の代わりにLerp(線形補完)関数が使われます。結果、同期されたオブジェクトのラバーバンド現象が発生します。
Extrapolateのオプション
Extrapolationは速度、最後の更新から経過した時間、最後に受信した位置を基にオブジェクトの実際の位置を推定します。頻繁に速度を変えないオブジェクトに適しています。
急に方向を変えるオブジェクトの場合は正確な位置の推定ができないため、新しい位置に更新する際に動作が乱れてしまいextrapolationに適していません。
Disabled(無効): Extrapolationは適用されません
SynchronizeValues(値の同期): このモードでは最後の更新から経過した時間を、元の更新で送信する同期速度及び回転速度と掛けます。これが一番正確な方法ですが、送信されるデータの量は増えます。
SetSynchronizedValues( Vector3 speed, float turnSpeed)
を呼んでローカルのGameObjectの速度と回転速度を定義してください。EstimatedSpeed(推定速度): このモードでは最新の位置と最後の位置の間の距離を計算して速度を推定します。
FixedSpeed(一定速度): このモードではオブジェクトの位置をextrapolateするために使う速度を決めることができます。
Rotation(回転)とScale(スケール)の同期
回転とスケールのinterpolationオプションは僅かしかありません。オブジェクトの実際の回転やスケールは審美の問題で、ゲームプレイに影響がない場合がほとんどです。interpolationオプションは次の通りです:
- Disabled(無効): 新しい値を受信したら即時にオブジェクトに適用します。
- RotateTowards/MoveTowards: オブジェクトがゆっくりターゲットに向かって回転/スケールします。
- Lerp: オブジェクトを指定値に向かって回転/スケールするために使う機能です。
Mecanim Animator設定
このデモではアニメーション特有のデータを送らずにアニメーションを同期させる方法を説明しています。このデモの動作やアニメーションの動きはRPGMovement
クラスで実施されます。 Update()
関数は次のように設定します:
C#
void Update()
{
if( m_PhotonView.isMine == true )
{
UpdateRotateMovement();
UpdateForwardMovement();
UpdateBackwardMovement();
UpdateStrafeMovement();
UpdateGravity();
}
UpdateAnimation();
}
動作が処理されるのは、このオブジェクトが実際にプレイヤに従属していて、ネットワーク化された動作がPhotonTransformView`で処理される場合のみです。
しかし、リモートオブジェクトのアニメーションの更新は行います。Animatorでは複数のパラメータが設定されています。動作のアニメーションに関連しているのはSpeed
とDirection
です。
これらの値はキャラクタの最新の位置と、最後の更新時の位置の差から計算します。
C#
void UpdateAnimation()
{
Vector3 movementVector = transform.position - m_LastPosition;
float speed = Vector3.Dot( movementVector.normalized, transform.forward );
float direction = Vector3.Dot( movementVector.normalized, transform.right );
m_Animator.SetFloat( "Speed", speed );
m_Animator.SetFloat( "Direction", direction );
m_LastPosition = transform.position;
}
キャラクタの前方ベクトルを使って速度と方向の差を測定して、Animatorにパスすることができます。これらの値を位置を基に計算することによりPhotonTransformView
から受信した位置の更新が計算に適用され、同期オブジェクトのアニメーションが動きます。