37.9K Views
June 23, 22
スライド概要
Fusionの新機能を 個人ゲーム開発者の立場からレポート 2022/06/23 新しいUnity向けマルチプレイSDK "Photon Fusion" イントロセミナー by ニム式
自己紹介 ● ● ● 名前 ニム式(通称ニム) サイト http://nimushiki.com twitter https://twitter.com/ni26mu ● ● ● 都内勤務のWEB寄りエンジニア 数年ぶりにゲーム作りに復帰 オンラインゲーム開発に初挑戦 2
華麗に復帰! だが1週間の壁に阻まれ 敗北… 3
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 4
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 5
Photon Fusionとは ● リニューアルされたPhotonシリーズのひとつ ○ ○ ● 2022年3月にリリース PUN2の後継 Photonシリーズ ○ Realtime ■ Fusion ■ Quantum ■ Voice ■ Chat 6
Photon Fusionとは ● ● ● オンラインマルチプレイ開発向けの製品 状態転送ネットコードSDK(後ほど解説) 新機能(後ほど解説) ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム async/awaitベース(非同期) WebGL対応 7
状態転送ネットコードSDK ● ネットコード ○ ● どうやって同期させるか 状態転送 ○ ○ ○ ゲームの状態を転送しあう ローカルでゲームを復元するための全データ 入力を転送しあう製品も存在(Photon Quantum) 8
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 9
導入手順 ● 公式チュートリアル(日本語)通りに進めればOK ○ https://doc.photonengine.com/ja-jp/fusion/current/fusion-100/fusion-101 10
簡単な解説① ● Unityプロジェクトの作成はいつもどおり ○ ● Unity 2020.3.x LTS以降が対象 Fusion SDKをダウンロードし、プロジェクトにインポート ○ ○ ○ チュートリアルはリンク切れ… サイト右上、「SDK」から探す https://doc.photonengine.com/ja-JP/Fusion/current/getting-started/sdk-download 11
簡単な解説② ● ● ● 公式サイトからサインイン(アカウントの作成) 新しくアプリを作成 アプリケーションIDをコピー 12
簡単な解説③ ● UnityEditorで設定 Fusion → Fusion Hub → Fusion Setupを開く Fusion App IdにAppIDをペースト ○ ○ ● 完了 13
簡単な解説④ ● オプション設定画面の表示方法 14
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 15
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 16
ティックベースシミュレーション ● ティック ○ ● スナップショット ○ ○ ● 実時間とは切り離された、Photon Fusionが持つ内部時間単位 各ティック毎に”ゲーム世界の唯一正しい状態”を保存したデータ 以降の説明でよく出てきます 各クライアントはスナップショットを使いゲームを進行 ○ =ティックベースシミュレーション 17
ティックベースシミュレーション 補足 ● ● ● ラグに強く、各種補正機能が使える 開発者が実装を行う必要はない Time.DeltaTimeはゲーム進行とズレる可能性がある ○ 必要であればRunner.DeltaTime に置き換える 18
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 19
ネットワークトポロジー複数対応 ● サーバー型 ○ ● プレイヤーホスト型 ○ ● ホスト/クライアントの構成 共有モード ○ ○ ● サーバー/クライアントの構成 上記2つの中間のような構成 Photonサーバーがホストの役割をする シングルモード ○ オフライン用 20
ネットワークトポロジーの設定 接続処理時に指定するだけ modeに入れるもの ● ● ○ ○ ○ ○ ○ GameMode.Server サーバーに接続 GameMode.Host ホストとして接続 GameMode.Client クライアントとして接続 GameMode.Shared 共有モードで接続 GameMode.Single ローカルで動作(ホストと同じような動作) await _runner. StartGame (new StartGameArgs () { GameMode = mode, // ネットワークトポロジーの設定箇所 SessionName = "TestRoom" , Scene = SceneManager. GetActiveScene ().buildIndex }); 21
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 22
物理挙動 ● ● PhotonFusionが同期用のコンポーネントを提供 実装は以下のコンポーネントをアタッチ ○ ○ ○ Rigidbody NetworkObject NetworkRigidbody NetworkRigidbody NetworkObject 23
物理挙動 補足 ● 同期が必要ない物理 ○ ● UnityのRigidbodyだけでOK 一切の同期が必要ない場合 ○ オプションで物理の同期をオフにする 24
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 25
通信とレンダリングの関係(補間なし) ● 帯域には限界がある ○ ● 通信周期は描画周期より遅くならざるを得ない 通信は正確な周期で到達しない ○ 60Hz →0.016/s →ping16 通信とレンダリングを同期させるとぎこちなくなる 26
スナップショット補間 ● スナップショット間のレンダリングを補間 バッファしておく 27
スナップショット補間 設定 ● ● 特になし TickRateの項目は多少関係あり 28
小休止… 29
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 30
ラグ補正ヒットボックス ● 通信には遅延がある ○ ○ ● WYSIWYGのゲームプレイ体験は非常に重要 ○ ○ ○ ● 各マシンのゲーム内時間が同じになることは稀 クライアントもサーバーも同様 見た目と処理の結果が一致すること WYSIWYG=What You See Is What You Get 遅延が天敵 ラグ補正ヒットボックス ○ ○ 位置情報履歴を保存 過去にレイキャストを行うことが可能 31
ラグ補正ヒットボックス 例 ● FPSでの例 ○ ○ プレイヤーAが、物陰に隠れる直前のプレイヤーBを狙撃 プレイヤーBは、自身のクライアント上では既に隠れ終わっている Aの世界 Bの世界 プレイヤーB プレイヤーA プレイヤーB プレイヤーA 32
ラグ補正ヒットボックスがない場合 チーターの世界 プレイヤーB ● サーバーが判定する ○ ○ ● クライアントが判定する ○ ○ HIT!! クライアントと違う時間で処理 そのため当てるのは困難 当てられる ただしチートしやすい Aの世界 プレイヤーA サーバーの世界 プレイヤーB プレイヤーB !! HIT!! プレイヤーA MISS プレイヤーA 33
ラグ補正ヒットボックスがある場合 Bの過去の世界 プレイヤーB ● プレイヤーA ○ ● ! HIT… 画面の通り射撃判定をする プレイヤーB ○ ○ Aの結果の時間まで遡る ヒットボックスがそこにあったか確認 プレイヤーA Aの世界 Bの世界 プレイヤーB プレイヤーB ? HIT… HIT!! プレイヤーA プレイヤーA 34
ラグ補正ヒットボックス 設定 ● Use Lag Compensation ○ ● Hitbox Buffer Size ○ ● ラグ補正ヒットボックス機能自体のオンオフ バッファするスナップショットの数 Debug ~~ ○ デバッグ表示 35
ラグ補正ヒットボックス 実装 ● ● ● ルートにHitboxRoot 子にHitbox Runner.LagCompensation.Raycastメソッドを利用 36
ラグ補正ヒットボックス 実装ポイント ● ● ● 静的なものにはColliderをつかう HitboxとColliderのレイヤーは分ける 入れ子OK 37
ラグ補正ヒットボックス レイヤー分け ● Raycast ○ ○ ○ ● Hitbox Hitbox レイヤーA Hitboxに当って欲しい 静的Colliderに当って欲しい 動的Colliderに当って欲しくない 静的Collider 静的Collider レイヤーA レイヤー ○ ○ レイヤーA ■ Hitbox ■ 静的Collider レイヤーB ■ 動的Collider 動的Collider 動的Collider レイヤーB ラグ補正ヒットボックス用 レイキャスト 38
ラグ補正ヒットボックス ● ● ● WYSIWYGの体験は非常に重要 手軽にそれを補強 負荷の高い処理なので使いすぎに注意 ○ ○ Unity標準のcolliderも併用する レイヤー分けも有効 39
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 40
レプリケーションシステム ● レプリケーションシステム ○ ○ ● スナップショットのレプリカ(複製)作成方式 その適用処理 レプリケーションモード ○ どんなレプリカを作成するか ■ Delta Snapshots(デルタスナップショット) ■ Eventual Consistency(結果整合性) 41
レプリケーションモード の前に ● オンラインゲームの同期オブジェクト数は様々 ○ ○ ○ ● 状態転送方式は通信量が多い ○ ○ ● 1vs1のターン制バトル チームFPS 千人規模のMMORPG ローカルでゲームを復元するための全データを同期 同期オブジェクト数増加=通信量増加 通信量を節約する ○ ○ スナップショットは差分を転送 自分自身の周辺や特定のオブジェクトに限定 ■ =レプリケーションモード 42
レプリケーションモード① 結果整合性 ● ● ● ● Eventual Consistency 自分の周辺や特定のオブジェクトに限定したスナップショットを転送 プレイヤーやオブジェクトが多い、ワールドが広い場合有効 MMO、バトルロイヤル 一部を同期 プレイヤーの同期範囲 クライアント サーバー 43
レプリケーションモード② デルタスナップショット ● ● ● ● Delta Snapshots オブジェクトの完全なスナップショットを転送 プレイヤーやオブジェクトが少ない、ワールドが狭い場合有効 格闘ゲーム、チームFPS オブジェクト 全て同期 プレイヤー クライアント サーバー 44
レプリケーションモード 設定 Eventual Consistencyモード ○ ○ Object Interestが出現、オンにするとInterest Management Settingsが有効に NetworkObjectコンポーネントにInterest Management Settingsの項目が出現 ■ 誰が同期(情報の取得)をするか、という設定 Object Interest 出現 ● 出現 45
Object Interest 設定 ● AreaOfInterest ○ ○ ○ ● AllPlayers ○ ○ ○ ● 別名:関心領域 AOIが設定されたオブジェクトのその範囲に入った場合に同期される プレイヤーや大抵のオブジェクト(一例) 別名:グローバルオブジェクト すべてのプレイヤーが同期する レイドボス、GM、NPC(一例) ExplicitPlayers ○ ○ ○ 別名:カスタムインタレストマネジメント 専用フラグを立てられたプレイヤーのみ同期する イベントキャラ、アシスタントキャラ(一例) 46
Object Interest 図解 ● AreaOfInterest ○ ○ AOIが設定されたオブジェクトのその範囲に入った場合に同期”される” プレイヤー、オブジェクト プレイヤーA ● AllPlayers ○ ○ ● すべてのプレイヤー NPC ExplicitPlayers ○ ○ AoIの範囲 専用フラグを立てられたプレイヤーのみ コンパニオンキャラ プレイヤーC プレイヤーB 47
AreaOfInterest(関心領域) 実装例 protected enum AuthorityType { InputAuthority = 1, StateAuthority = 2 } [SerializeField] protected AuthorityType TargetPlayerBy = AuthorityType.InputAuthority; public float Radius = 32f; //AoIの範囲の半径 AoIの範囲の半径 var target = TargetPlayerBy == AuthorityType.InputAuthority ? Object.InputAuthority : Object.StateAuthority; if (target) { Runner.AddPlayerAreaOfInterest(target, position: transform.position, radius: Radius); } } 中心は自身 public override void FixedUpdateNetwork() { AoIの範囲の半径 48
アジェンダ ● ● ● Photon Fusionとは 簡単な導入説明 新機能の紹介 ○ ○ ○ ○ ○ ○ ● ● ティックベースシミュレーション ネットワークトポロジー複数対応 物理挙動 スナップショット補間 ラグ補正ヒットボックス レプリケーションシステム PUN2との比較 まとめ 49
同期内容の種類 ● 入力 ○ ● 高頻度 ○ ○ ● オブジェクトの位置 アニメーション 低頻度 ○ ○ ● マウス、キーボード、マイク プレイヤーステータス 対戦ルーム情報 不定期 ○ ○ 特殊イベント ステージ・ラウンドの進行 50
PUN2との比較 同期手段 PUN2 入力 Fusion NetworkInput オブジェクト同期 高頻度 PhotonStream オブジェクト同期 [Networked] 低頻度 不定期 カスタムプロパティ RPC(Remote Procedure Call) 51
PUN2との比較 入力 PUN2 入力 Fusion プロパティに取得 INetworkInputを継承した構造体で保存 PhotonStream.SendNext(Object) NetworkInput.Set(INetworkInput) PhotonStream.ReceiveNext() NetworkInput.GetInput(INetworkInput) 必要 (とはいえifで分岐するだけ) 不要 同期方法 自他の判別 52
PUN2との比較 同期方法 高頻度 PUN2 名称 同期方法 その他 Fusion オブジェクト同期 オブジェクト同期 IPunObservableを実装 PhotonStream NetworkBehaviourを継承 SendNext,ReceiveNextメソッドで同期 したいものを送受信する プロパティに[Networked]をつける 53
PUN2との比較 同期方法 低頻度 PUN2 名称 カスタムプロパティ Fusion オブジェクト(プロパティ)の同期 SetCustomProperties 同期方法 プロパティに[Networked]をつけるだけ CustomProperties[key] 型 Hashtable(Dictionary)しか扱えない 型はわりと何でも OK 54
PUN2との比較 同期方法 不定期 RPC
PUN2
設定
メソッドに[PunRPC]属性をつける
Fusion
メソッドに[Rpc] 属性をつける
PhotonView.RPCメソッドで呼ぶ
実行方法
通常通りメソッドを呼ぶ
メソッド名を文字列で指定 する
[PunRPC]
実装例
void ChatMessage(string a, string b){ }
[Rpc(RpcSources.InputAuthority, RpcTargets.All)]
ーーー
public void RPC_SendMessage(string message){ }
ーーー
PhotonView photonView = PhotonView.Get(this);
RPC_SendMessage("Hello world!");
photonView.RPC("ChatMessage", RpcTarget.All,
"jup", "and jup.");
55
まとめ ● アーキテクチャが一新 ○ ○ ● 強力な機能を手軽に使用可能 様々なゲームタイプに対応 PUN2に比べ実装はかなり楽に ○ 物理挙動やプロパティの同期、RPCの仕様変更はありがたい 56
ご清聴ありがとうございました 57