← 戻る

UEとUnityがなかよくする方法 - Unite 2025をみて、実際に作ってみた

2025-12-01

この記事は 趣 Advent Calendar 2025の 1 日目の記事です。 今年もたくさんの趣メンバーが集まりました。トップバッターとなり大変恐縮ですがよろしくお願いいたします。


先日 Unity の開発者カンファレンス Unite 2025 のキーノートで、「来年 Unity で開発したゲームを Fortnite 上で公開することができるようになる」というアナウンスがあった。

この発表はかなりインパクトがあった。Fortnite は Unity ではなく Unreal Engine(以後 UE)で開発されており、まったく技術が異なる。 ゲーム開発者の中でも「どうやっているのか」「本当にできるのか」という話題が盛り上がっていた。 この記事では、実際に動く PoC の開発を通じて、これの技術的な実現可能性を探っていきたい。 一般的なゲームの通信方式について興味ある人の参考になるよう、必要な技術の説明はかなり詳しく行っている。

(この記事の内容は、あくまで neguse 個人の推測であり、当たるも八卦当たらぬも八卦である。詳細は来年公開されるという話なので答え合わせが楽しみである。)

結論を先にいうと、こういうのができた。

推測の材料

推測をする上で参考になるのが、Epic Games の CEO であるTim Sweeney氏のツイートやリプライである。

まとめると以下のようになる。

以降では、これがどういうものなのか、実現可能なのかを解説しながら探る。

マルチプレイヤーゲームの通信トポロジって?

具体的な方法に入る前に、そもそも client-server ってなんぞやという話がある。 以後の話を理解するための材料として、ここではマルチプレイヤーゲームの一般的な仕組みについて述べる。 特に新しい情報があるわけではないので、ある程度知っている方は飛ばしていただいて問題ない。

マルチプレイヤーのゲームでは、ノード(ゲーム機で動いているゲームアプリケーション)間がどのように接続して通信するかの方式(これを通信トポロジという)が大きくわけて 3 つある。 この分け方はある程度一般性はあるものの呼び方にブレがあるため、あくまでこの記事内での呼び方・定義であることに注意。

以下、それぞれを説明する。どれが優れているということはなく一長一短で、ゲームの特性によって向き不向きが存在する。

full mesh

A Node A B Node B A--B C Node C B--C C--A

full mesh では各ノードは対等の関係で、各ノードは他の全ノードへの接続を行う。 full mesh のメリットはノード間が直接通信されることでレイテンシが少ないことが挙げられる。 一方デメリットは、現実的にはノード数や通信量を増やすことが難しいことが挙げられる。

ノード間の直接通信には一般にNAT Traversal技術が必要で、これの成功率は 100%ではない。 full mesh では全てのノードが互いに接続する必要があるため、たとえどこか 1 つのノード間の通信ができないだけで通信が行えなくなる。 またあるデータを送信する時、自分以外のすべてのノードにデータを送るため通信量も O(ノード数)で増える。

(このデメリットを解消するため、relay server を使った通信トポロジもあるが今回は割愛する)

full mesh は、たとえば格闘ゲームのオンライン対戦に向いている。格闘ゲームは相手の反応を伺いながら自分の行動を決める特性上レイテンシにシビアであり、またコントローラの入力データのみ同期して各クライアントで全く同じ結果を再現する方式(deterministic)で実装できるため、少量の通信を対等な関係のノードに配ることで実現できるためである。

listen server

A Node A B Node B A--B C Node C A--C

listen server はどれか 1 つのノードが「クライアント兼サーバ」(ホストと呼ばれることもある)となり、他のノード(ゲストと呼ばれることもある)はサーバとだけ接続して通信を行う。 この図でいうと、Node A が listen server となり、他の Node B/C は A とだけ接続を行う。

listen server のメリットは、非サーバノードがサーバとだけ接続すればいい点、正となるゲーム状態をサーバが持てる点が挙げられる。

接続については、必要な接続本数が減ることで全体としての接続の成功率が上がるのである。

ゲーム状態の話については、たとえばエルデンリングやモンスターハンター、あるいはスプラトゥーンのようなゲームで、敵に自分が弾を撃って攻撃することを考える。 このとき、Node A では攻撃が当たって倒れたが、Node B では攻撃が当たらなかったという異なる結果になることは回避したい。 listen server では「Node A の結果が正しい」ということにしてその結果を他の Node に同期するという仕組みで、状態のズレを容易に回避することができる。 またこれらのゲームでは「コントローラの入力が即座に自分のキャラクターに反映できることが重要」かつ「オブジェクトの物理シミュレーションなど状態を巻き戻すことが困難な計算が多い」ため、一時的なサーバとのズレを許容しつつ重要なデータのみ最終的に整合するよう処理を進めていく方式となっていることが多い。

一方 listen server のデメリットは、サーバに負荷が集中する点、ゲームの公平性やチート耐性が担保されない点が挙げられる。

なぜサーバに負荷が集中するかというと、それは非サーバノードの接続本数は full mesh より減ったものの、サーバは自身以外の全ノードに接続し通信を行う必要があるからである。 通信処理によってサーバの負荷が高まる結果、サーバとなったユーザのゲーム体験に影響が出たり、あるいはサーバがクラッシュしたり接続が切れた場合全員の通信が行えなくなってしまう。 (切断の影響についてはホストマイグレーションという技術で緩和しうるが、これはこれで UE でのサポートが無いなど茨の道である。)

ゲームの公平性への影響は、つまりサーバが非サーバより有利になるのである。 サーバ以外のノードは正となる状態を受け取るまで通信時間が必要だが、サーバは通信を行わなくても即座に状態がわかるため、一般的に有利になりやすい。 また通信をごまかしたり状態を改ざんするようなチートについても、非サーバでの行為はサーバへのリクエストを拒否する等で制限しやすいが、サーバでの行為は「正となる状態」を直接コントロールできるため制限しにくい。 これらから、公平性やチート耐性が重要な競技ゲーミング分野においては listen server 方式は明確なデメリットがある。

dedicated server

S Node Server A Node A S--A B Node B S--B C Node C S--C

dedicated server は listen server に似ているが、サーバは専業となりクライアントと分離されている点が異なる。 この図でいうと、Node Server が dedicated server となり、他の Node A/B/C は Node Server とだけ接続を行う。 dedicated server はゲームパブリッシャーが提供することもあれば、ユーザ環境で自由に起動できる場合もある。 dedicated server では一般にゲームプログラムの画面描画処理が除かれた専用のビルドやモードが用意され、ゲームアプリケーション本体より少ないリソースでの稼働が可能である。

dedicated server のメリットは、前述の listen server のメリットをすべて享受したうえで、さらにデメリットを潰すことができる点である。

server を分離し専用のマシンで動作させることで、負荷をコントロールでき通信が安定しやすい。 server をユーザの手が届かない場所で動作させることでチートを防ぐことができ、通信にかかる時間も(サーバまでの各自の物理的・ネットワーク的な距離という要素はあるものの)一律公平にかかる。 Minecraft や ARK: Survival Evolved, Rust のような「ゲームを起動しているかどうかによらず NPC が動き、世界の時間が経過する」ということも実現できる。

dedicated server のデメリットは、とにかくインフラコストがかかるという点である。

パブリッシャーが提供する場合はパブリッシャーのインフラコストがかかる。 このことはつまり、定期的な収益が見込めない場合サービスの維持が難しくなるということである。 パッケージとしてある程度まとまった額を払いその後は無料で遊べるというスタイルの売り方のゲームだと、発売からの時間経過により売上規模がシュリンクしていき、いずれサーバインフラコストを賄うことができずサービスを閉じざるを得なくなる。 そのため月額課金や小額課金などで「新規ユーザ数よりアクティブユーザ数」に応じた収益の手段を確保しておかないと、長期的なサービスの提供は難しい。

ユーザ環境で稼働させる場合でもユーザ側でインフラをもつコストがかかる。 ロリポップ! for GamersNitradoのような複数のゲームサーバに対応したサードパーティーのサービスや、あるいはMinecraft Realmsのようなゲームパブリッシャー自身が提供するサービスもあるが、どれも月額利用料がかかり、また接続数に応じて必要となるキャパシティは増えるため多人数で遊ぶためのサーバはさらに高額になる。

UE の通信方式

さて、UE や Fortnite がどう通信しているかを解説する。

UE では、標準の機能として listen server, dedicated server の 2 つに対応している。 これは UE 自体がUnrealUnreal Tournamentといった FPS のために開発されたという出自による。 FPS も前述のとおり「コントローラの入力が即座に自分のキャラクターに反映できることが重要」かつ「オブジェクトの物理シミュレーションなど状態を巻き戻すことが困難な計算が多い」ゲームであるため、server が必要である。

UE ではノード間の同期をサーバからの状態の同期「Replication」と、ノード間での処理の命令「RPC」という形で行えるようになっており、これらを組み合わせて使うことでサーバで状態を整合させる仕組みを容易に実装できるようになっている。 逆にいうと、full mesh の例で挙げたような「キー入力だけ同期して全状態を再現性ある形で実現する」方式には標準では対応していない。 これは UE で格闘ゲームが作れないということは意味しておらず、実際鉄拳 8GUILTY GEAR -STRIVE-など UE 製格闘ゲームは数多く存在するが、それらはおそらく UE 標準の通信の仕組みは使っておらず、独自の方式、あるいはサードパーティーのミドルウェアを採用していると思われる。

UE での通信の実装方法に興味のある人はMultiplayer Network Compendiumがわかりやすい入門記事になっている。

Fortnite は、基本的に dedicated server で動作していると思われる。 たとえばバトルロイヤルであれば 1 ゲーム最大 100 人が接続するが、だれか 1 人がゲームを終了しても他の 99 人はゲームが引き続き遊べるためである。

では、Unity と UE をつなぐ通信方式は?

だいぶ事前準備が長くなったが、ここからが本題である。

ずばり dedicated server と推測する。ただしプロトコルは新規で、UE の方式ではないと思われる。

ここまで読まれた方なら、前述の Tim Sweeney 氏のツイートにあるIt’s a lot closer to the traditional client-server comms protocols of multiplayer gamesから、listen server ないし dedicated server であることがわかるかと思う。

またユーザが動かすゲーム自体はあくまで Fortnite で、server のみ Unity とすることで API 非依存にするというアプローチなので、listen server でもない。 したがって dedicated server なのである。

通信プロトコルも、UE の Replication や RPC に則ることのデメリットが大きい(Replication や RPC のデータ構造は API に依存するため)ため、おそらく独自のものである。(そもそも新しく開発したという発言があるが)

図にするとこうである。

cluster_epic Epic Games Server cluster_unity Unity製 Dedicated Server (開発者が作成) S Fortnite用 Server Component A Fortnite (UE) S->A B Fortnite (UE) S->B unity protocol C Fortnite (UE) S->C

ゲーム開発者は Unity でゲームを開発する。ここに Fortnite との通信ができる dedicated server として動作するための専用コンポーネントを仕込んでおく。

Epic Games は開発者が作った Unity 製 dedicated server を(Fortnite の dedicated server のように)独自のインフラで稼働させ、ユーザ環境の Fortnite から接続できるようにする。 こうして Unity で実装されたゲームコンテンツが Fortnite から体験できるというわけである。

やってみたことの紹介

ということで、ここから PoC として作ったものを紹介する。 百聞は一見にしかず。

Unity と Unreal Engine とで、オブジェクトの状態が同期されるような仕組みを作った。 これにより、Unity 側のコンテンツが、そのまま UE で遊べるようになった。

(今は手抜きで Unity 側は Editor で起動しているが、これはそのまま Dedicated Server ビルドにしても動く…はず)

ちなみにざっくり動くようになるまで 2 日間ほどかかった。 初日でそれぞれのビルド環境を用意してソケット生成までを書き、2 日目でオブジェクト同期を(ほぼほぼ Claude Code が)書いた。

詳細な解説

こちらのソースコードを見ながら読んでください。 https://github.com/neguse/usync

ざっくり以下のようなことをやっている。

cluster_unity Unity (Server) cluster_ue Unreal Engine (Client) UC Server Component (MonoBehaviour) GI GameInstance (UDP受信) UC->GI オブジェクト状態 UO Game Objects (ID,位置,回転,スケール) UO->UC 状態取得 GI->UC プレイヤー入力 UA Actors (位置,回転,スケール) GI->UA 状態反映

Unity 側では MonoBehaviour ベースの Server component がゲームオブジェクトの状態同期を行っている。 具体的には以下のことをしている。

UE 側では、 GameInstance でゲームオブジェクトの状態同期を行っている。 具体的には以下のことをしている。

通信パケットは、ざっと以下のような感じ。

  === Server -> Client ===

  ServerPacket = Timestamp ObjectCount { Object } ;

  Timestamp   = int32 int32 ;  (* Server time in microseconds, low/high 32bits *)
  ObjectCount = int32 ;

  Object = InstanceID ObjectType ClientID Position Rotation Scale ;

  InstanceID = int32 ;         (* Unity Transform.GetInstanceID() *)
  ObjectType = uint8 ;         (* 0: Unknown, 1: Sphere, 2: Cube, 3: Capsule *)
  ClientID   = int32 ;         (* Owner ClientID for Capsule, 0 otherwise *)
  Position   = Vector3 ;
  Rotation   = Quaternion ;
  Scale      = Vector3 ;

  Vector3    = float float float ;       (* X Y Z *)
  Quaternion = float float float float ; (* X Y Z W *)


  === Coordinate Conversion (Unity -> Unreal) ===

  Position: (X, Y, Z) -> (X * 100, Z * 100, Y * 100)
  Rotation: (X, Y, Z, W) -> (X, Z, Y, -W)
  Scale:    (X, Y, Z) -> (X, Z, Y)

つまりヘッダとしてタイムスタンプとオブジェクトの数が入り、その後オブジェクトの数だけプロパティがそのまま並んでいるだけである。 たったこれだけで同期が実現できるのである。

やってみたことに足りてないこと

で、これで動いた!完成!かというと全然そんなことはない…

同期プロトコルの機能拡充

今はとにかくシンプルな実装になっているが、サーバ・クライアント共にいろいろ足りない点が多い。

このへんをやりたい場合は、Gaffer On GamesNetworked Physicsシリーズを一通り読んでおくとよい。 かなり詳しく、具体的な内容が記されている。

アセット(3D モデル等)は?

言及がほぼないので推測が難しいのだが、Unity からエクスポートしたアセットを UE 側に取り込める形式に変換するのが王道だろうか。 その場合 glTF や USD のようなオープンなフォーマットを介するのが有力と思われる。

あるいは Fortnite や UE 用のアセットを Unity からも使えるように両対応する仕組みを用意して、両対応アセットのみ利用可というアプローチもありうる。 その場合FabUnity Asset Storeとの連携が利用される可能性もある。

いずれにせよ、Unity と UE とではレンダリングパイプラインが異なるため、同じアセットを使ったとしても同じような見た目になることは担保しづらいように思う。

クライアントの処理は?

前述の通り、listen server / dedicated server は「クライアントとサーバの一時的なずれを許容することで、コントローラの入力が即座に自分のキャラクターに反映できる」手法だった。 このメリットを享受するためには、クライアントでもサーバと似た形で処理を動作させる必要がある。 たとえば「ボタンを押したら回避行動をとる」という仕様をクライアント上で遅延なく実行するには、そのロジックがクライアントにもサーバにも必要なのである。 今回の PoC の方式では、クライアントからサーバへはあくまで操作だけ送っている。 これだと動いた結果をサーバから受け取ってようやくクライアントに反映されるため、コントローラの入力が自分のキャラクターに反映されるまでに時間がかかり、これはゲームの特性によっては致命的である。

Unity/Epic Games がここを解消するつもりがあるのかどうか、またそのときに「プログラミング言語や API は一致する必要がない」という前述の話がどれぐらい維持されるかに関心がある。

自分の推測では、「プレイヤーキャラクターの挙動は最初のバージョンではカスタマイズできず、Fortnite のキャラクターがそのまま動かせるだけ」というのが落とし所なのではないかと思っている。 ここが変えられると、そもそも Fortnite のゲーム体験からずれてしまうという話もある。

まとめ

以上、Unite で発表された「Unity 製コンテンツを Fortnite に持ってこれる」という話を、Tim Sweeney 氏の発言をもとに、「UE と Unity がなかよくする方法」の仕組みを推測し、PoC を開発してみた。 実現可能性はだいぶ見えたが、一方で課題もある。 うまく実現されるのか。実現できたとしてはたしてその先はどうなるのか。 今後も注目していきたい。

(Verse がオープンソース化するという話は一体いつ… UE6 にはフォートナイト用の言語「Verse」が導入される?GDC 2024 の Verse 講演から見るアンリアルエンジンの今後)

で、おまえ誰?

今年フリーランスの個人事業主になったソフトウェアエンジニアのneguseといいます。 いままでゲーム/メタバースプラットフォームを 10 年以上開発してきて、主にリアルタイム通信やサーバを担当してきました。 この記事ぐらいの技術的な話ができ、いろいろ調べながら実装ができます。 なんか話したい方がいたらお気軽にご連絡ください。お返事できたらします。記事のご意見やご感想も大変ありがたいです。 SNS、固い話用フォームやわらかい話用マシュマロなどがあります。 (なお直近の空き稼働枠的な意味で、近々一緒にお仕事しましょう的なお話はお断りすることになる確率が非常に高いです。) https://www.neguse.dev/

おわりに

次の 2 日目は Tomohiro Nishimura さんの「趣」です。趣を感じていきましょう。