Unityで簡単にネットワーク同期が実現できるPUN(Photon Unity Network)。
v1.50からPhotonTransformViewなるTransform同期をサポートしてくれるコンポーネントが追加されました。
そもそもTransformの同期とは、「キャラクタの位置・姿勢・大きさ」の同期を意味します。
Transformの同期が上手くいかないと、突然キャラクタがワープしたり、カクカクの動きをしたりととてもじゃないが快適とは言えないゲームになってしまします。
今まではTransformを滑らかに同期してあげるためにはスクリプトを書き、OnPhotonSerializeViewでパラメータ同期をした上でスクリプトで補間を入れてあげる必要があり、そこそこ手間のかかるものでした。
(たまにPhotonViewに直接Transformを指定し、動きがカクカクになってしまっているゲームをリリースしている人を見かけます。正気ですか?)
その面倒臭かったTransformの滑らかな同期が、PhotonTransformViewを使うことでとても簡単にできるようになりました。
そこで今回はこちらの使い方を紹介したいと思います。
#PhotonTransformViewの使い方
1. GameObjectにComponentを貼り付ける
- PhotonView
- PhotonTransformView
Transformの同期を行いたいGameObjectに上記のコンポーネントを貼り付け、PhotonViewのObservedComponentsにPhotonTransformViewを追加します。
PhotonViewの監視対象にPhotonTransformViewを追加
2. 同期したい要素にチェックを入れる
同期したい対象にチェックを入れます。
PositionとRotationだけの同期で良いなら「Synchronize Position」「Synchronize Rotation」の2つをチェックすればOKです。
3.パラメータ同期の手法を設定する
Synchronize Positionの設定
- Enable teleport for greater distances
同期ズレが起きてオブジェクトの位置が大幅にズレた時に、オブジェクトをワープさせて補正するかどうかの設定です。
ONにすると指定距離以上離れた時にオブジェクトの座標が強制的に上書きされます。
アクションゲームなど、相手の現在位置が重要なゲームではONにした方が良いかもしれません。
- Interpolate Option
補間処理。設定することでオブジェクトの動きが滑らかに同期されるようになります。
詳しくは後述に。
- Extrapolate Option
補外処理。未来の座標を予測してオブジェクトを予め移動させておくことで同期による遅延を低減することができます。
急激に速度が変化したりする動きが予測できないオブジェクトには使わない方が良いです
- Draw synchronized position error
ONにするとSceneViewに同期座標が描画されるようになります。たぶんデバッグ用かな。
Interpolate Optionの設定
- Disable
補間を使わない設定です。動きがカクカクになるのでオススメしない。
- Fixed Speed
常に一定速度でオブジェクトを追従させて補間します。
同期対象のオブジェクトの速度が固定されている場合に有効だそうです。
- Estimated Speed
受け取った「直前の座標」と「現在の座標」の差分を現在の速度と仮定してオブジェクトを移動させて補間します。
ゆっくりと加速/減速するオブジェクトに有効だそうです。
- Synchronize Values
スクリプト側で直接現フレームにおける速度と回転速度を与え、それを使って補間します。
激しく動くオブジェクトに最適。アクションゲームにオススメします。
使い方はスクリプトのUpdate内でPhotonTransformView.SetSynchronizedValuesにspeedとturnSpeedを指定してあげればOKです。
SetSynchronizedValues(Vector3 speed, float turnSpeed)
private PhotonTransformView photonTransformView;
private CharacterController characterController;
void Start()
{
photonTransformView = GetComponent<PhotonTransformView>();
characterController = GetComponent<CharacterController>();
}
private void Update()
{
/*
*
ココらへんで移動処理とか
*
*
*/
if (photonView.isMine)
{
//現在の移動速度
var velocity = characterController.velocity;
//移動速度を指定
photonTransformView.SetSynchronizedValues(speed: velocity, turnSpeed: 0);
}
}
turnSpeedはExtrapolate OptionでSynchronize Valuesを指定した際に使用されるパラメータであり、Interpolate Optionのみを使用する場合は不要(0指定で良い)です。
- Lerp
お馴染みの線形補間。面倒くさい時はとりあえずコレ。
激しく動くオブジェクトも滑らかに同期されるようになるが、動きがワンテンポ遅れるので注意。
Extrapolate Optionの設定
だいたいInterpolate Optionと同じなので省略。
ただしInterpolateと違い、ちゃんと設定しないと凄まじく同期ズレするので注意。わからなかったらDisableでいいかも。
Synchronize Rotationの設定
Rtationには補間処理しかありません。
- Disable
補間しない設定。激しく回転するオブジェクトの場合は回転がカクカクになります。
- Rotate Toward
指定速度で補間する設定。
- Lerp
線形補間。面倒ならこれでいい気かも。
Synchronize Scaleの設定
- Disable
補間しない設定。
- Rotate Toward
指定速度で補間する設定。
- Lerp
線形補間。
4. 実際に動かして試す
パラメータの値を調整して、一番自然に見える値を設定しましょう。
まとめ
PhotonViewとPhotonTransformViewの2つのコンポーネントを貼るだけで滑らかにTransformを同期できるようになりました。スクリプトを書かずに面倒くさい補間処理をやってもらえるのはとても楽で良いですね。
ただ自分が試したところ、Positionの同期はSynchronize ValuesにCharacterController.velocityを食わせるのが最も滑らかに同期するように感じました。結局スクリプトは書くことからは逃れられない。