CalendarCocos2d-xこんにちは、ガレージスタジオでネイティブシフト推進を行っている久富木隆一(@ryukbk)です。2014」16日目の記事です。今年も忙しい師走となりましたが、皆様いかがお過ごしでしょうか。Calendarなるものが世間で流行っているようですが、宗教的信条の無い者としてはどうなのと思いつつも、お祭りは何だかんだで放っておけない性分でございます。今回は、オンラインマルチプレイヤーゲーム、中でもアクションゲームの作り方について考えてみます。node.jsによるオンラインマルチプレイヤーアクションゲームのサンプルコードSantaShooterをご紹介します。e-sportsの盛んな海外を中心としたPCゲームの世界、特にFPSゲームエンジンでのネットワークを介したマルチプレイヤーモードの実装の変遷から、Cocos2d-xの最低限の使い方まで、マルチプレイヤーアクションゲームのクライアント/サーバー開発で意識すべき諸問題からの学びにより、実装に取り掛かるための端緒を提供できればと思います。国民とは、想像された政治共同体です。それは、内在的に制約されながら同時に独立主権的でもあるものとして、想像されているのです。国民が想像されたものであるというのは、最も小さな国民の構成員ですら、同輩のほとんどを知ること無く、会うことも無い、いわんや聞いたことすら無いにもかかわらず、各々の心の中には自分たちの交わりの場のイメージが生きているということによります。実のところ、顔合わせの原始的村落より大きな全ての共同体(あるいは原始的村落ですらも)は、想像上のものにすぎないのです。共同体は、真偽ではなく、その想像のされ方によって区別されるべきです。『想像の共同体』(1983:6)アメリカの政治学者ベネディクト・アンダーソンの代表的著作の、「どこかに真の共同体なるものがあるわけではなく、全ての共同体は想像の産物以上のものではない」と喝破した、冒頭の一節です。この、20世紀末に著された一文を読んで、皆さんは何を思い浮かべるでしょうか。私としては、19世紀以来の国民国家イデオロギーのスコープを超えて、21世紀のインターネット上に存在する、様々なコミュニティの有り様を想起させられます。サイバースペースと呼ばれていた想像の共同体は、今日では我々の日常生活と切り離すべからざる地続きの存在になっています。Shooter:一人称視点シューティングゲーム)のジャンルは、欧米で人気の主流です。マルチプレイヤーFPSの最も原始的な形態は、1対1でコンピューター同士を接続して行う、シンプルなP2Pの形式です。LAN上で、次にインターネットを介してマッチングを行いインターネット上で通信する形で、この対戦の形式が広まりました。私のようなオールドPCゲーマーにとって、たとえば「ドワンゴ」と聞いて思い浮かべるのは、まずもってこの、1990年代半ばに流行ったインターネットを介した対戦ゲームプレイサービスです。この、シンプルな1対1のP2P接続のつぎにやってくるのは、2台より多い複数台のコンピューターを全て相互に、フルコネクトのネットワークトポロジーで接続してプレイする、シミュレーションゲームのジャンルです。Strategy)ゲームは、この方式です。この方式は、「行進(lockstep)」方式とも呼ばれます。行進というのは、全ての参加メンバーのコンピュータ上で、ゲーム内部で区切られた一定時間の1単位(ターン)が同じように計算され、全てのコンピュータ上で1ターンが同じように経過したと全てのコンピュータが合意して初めて、ターンが1進むという、ターンベースでの進行を、歩調を横一列で揃えて行進していくさまになぞらえたことによります。いったRTSゲームは、軍勢のようなユニットをコントロールすることが多く、前述のFPSのような、激しいアクションはありません。軍勢に指示を出してからゆっくりと軍勢が動きだすアニメーションを表示するなどして、ユーザーの入力を少なくし、背後では、参加しているコンピュータ同士で時間を区切って通信を行い、ターン内で行える行動を制限しつつ、ターンを進めているのです。この形式の利点は、実装がシンプルなことです。全てのコンピュータが合意に達するまでターンが進まないので、ネットワーク接続が遅いコンピュータが参加していた場合、全員のゲーム体験の品質が落ちる全てのコンピュータが1ターンで同じ計算結果に達する必要が有るため、ゲーム内の挙動は全て決定論的(deterministic)である必要があるゲームが決定論的であるというのは、たとえば違うコンピュータで計算すると結果が違うような乱数はゲーム内で使えないということです。しても乱数的なものを使いたい場合、C++11のmt19937のような、シードを与えると同じ結果を得られることが保証されている擬似乱数を使う必要があります。この、決定論的でなければならないという点が、今日のモダンなゲームをマルチプレイヤー対応に作りこむ上で、障害となりうる点です。いうのは、モダンなゲームを効率的に作る上で欠かせない物理演算のエンジンは、高度なものであるほど浮動小数点演算器を活用するため、計算精度の問題から、異なるデバイス間で同一入力から同じ計算結果を保証できないものとなっているからです。全員のゲーム体験の品質が、最も遅いコンピュータに引きずられて悪化するというのは、特にアクションゲームでは、致命的な問題となります。冒頭で、共同体とは、共同で想像された幻想にすぎない、という言説を挙げました。ネットワーク上で、この幻想を維持するために必須なのが、遅延(ラグ/レイテンシー)の隠蔽です。回線の向こうでゲームプレイを共にするメンバーたちは、実際には地理的・物理的に遠く離れており、その通信は言うなれば互いに遠隔地同士で手紙をやりとりしているかのような、発送から受信までの間の時間的遅延を免れないものです。通信の遅延をいかに誤魔化し、儚い幻想を維持するか、そこにマルチプレイヤーゲームの全ての工夫が詰まっているといっても過言ではありません。マルチプレイヤーゲームの歴史に戻って、”Doom”のようなP2P方式の1対1デスマッチプレイの次にやってきたのは、”Quake”に代表される、多対多のチームプレイを可能とするクライアント-サーバー方式でした。ユーザーがアクセス出来ない領域を含むサーバー上でゲーム内の物事が全て起こり、ゲームプレイヤーが操作するクライアント群は、キーストロークをサーバに送って結果を受け取るだけのシンクライアント、ダムターミナルとなる、という方式です。この形式の利点は、サーバーが完全に掌握している空間内で起こる現象が常に優先されるため、チートが起こりにくいという点、そしてネットワーク接続が遅いプレイヤーが居たとしても、そのプレイヤーが不利になるだけで、他のプレイヤーはそのままプレイを続行できるという点です。チートに関しては、先述の行進方式でも計算結果に全員が同意する必要があるので実際にはさほど問題になりませんが、クライアント-サーバー方式のほうがより堅牢です。このモデルでは、全員が計算結果に同意する必要がなく、メンバーの途中参加・退出も可能です。この、クライアント-サーバー方式でのゲーム体験は、日本のモバイルゲームユーザーには、馴染み深いものです。データベースサーバーのスタックと、非力なフィーチャーフォン端末という組み合わせによるゲームプレイは、まさにこのクライアント-サーバー方式を(主に非同期ではありますが)踏襲しているからです。この方式でも、すべての計算をサーバー上で行ってから結果をクライアント群にブロードキャストするということをやっているだけでは、十分なゲーム体験品質を達成するには至りませんでした。VR社のCTO)が”QuakeWorld”(QW)で披露したのは、一部の計算をクライアント上で並行して行い、正しい計算結果がサーバーから届くまで、見かけ上のレイテンシーを隠蔽するという方法でした。ここではCarmackは、当時の彼のblog的な、fingerコマンドで返ってくる.planで、それまで強力なサーバーのみが世界の情報をすべて持っていれば良かったエレガントな構造が、クライアントもサーバーと同じような物理演算を行うための情報セットを持ち、計算リソースを消費する無駄が出てきた、という嘆きのポーズを表明していますが、その犠牲をユーザーが払うだけの価値をもたらす革新でした。prediction)部分のソースコードを閲覧可能で、解説記事もあります。クライアント予測は、クライアント上でもサーバー上で行われているシミュレーションの一部を実行することで、例えば自分が動く場合は、サーバーに自分が動くというコマンドを送ってその移動結果を待つという悠長なことをするまでもなく、クライアントローカルで先に動いたことにするという挙動になっています。他のプレイヤーの位置についても、情報が届く前に、手元にある情報を用いて、外挿法による補間(extrapolation)を行います。Reckoningとも呼ばれます。Networking“のベースとして、この分野で最も参照されるドキュメントです。ここで説明されているのは、3つのテクニックです。compensation)まず、クライアントサイド予測は、”QuakeWorld”でも導入されていますが、Valve版では、クライアントで予測したシミュレーション結果と、サーバーから届いたシミュレーション結果に齟齬が通じた場合は、サーバーから届いた結果はクライアントから過去に送ったキー入力の結果であるので、一旦はサーバーのシミュレーション結果をクライアントで受け入れるにしても、それ以降にクライアントに入力された操作情報をサーバーからの結果に重畳して適用するという形を取ります。クライアント側ではスライディングウィンドウにキー入力履歴を保存しておいて、サーバーから届いた結果を生じさせた入力以前のタイムスタンプの履歴は破棄し、それ以降の一連のキー入力をサーバーからの結果にあらためて適用し、その時点での新たなクライアント予測の結果に反映する、という挙動です。ある意味、gitのrebaseコマンドに似ていると言えなくもありません。rebase先(サーバーという変更履歴ブランチ)に、rebase元(クライアントブランチでの変更)を適用して、1続きの歴史を再構成するというわけです。Reckoningの発展形です。外挿法だと、プレイヤーが急に方向を変えたりジャンプしたりと、予測を破るような急制動をしやすいアクションゲームでは都合が悪く、他のプレイヤーなどのゲームを構成する物体(エンティティ)の挙動予測に失敗することが多いところ、サーバーから送られてくるゲーム内情報を数フレーム分バッファリングすることによって、複数フレームを用いてその間を内挿法的に補間し、必要に応じて外挿法を援用することによって、プレイヤーが目にする世界が全体的に遅延したものとなることと引き換えに、より精度高くなめらかな表示を実現するものです。最後に、ラグ補償は、ネットワークレイテンシーと、エンティティ補間によって導入された補間用バッファリングのレイテンシーの双方に、サーバーサイドで対策するもので、シューティングゲームで重要になる攻撃行動の結末を、ユーザーが自分のマシン上で目にしている情報を尊重するように補正するものです。いうことかというと、ユーザーは他のプレイヤーを的に銃を発砲するわけですが、ユーザーが目にしているのはサーバー上で過去に起こった事象なので、そのままだと、他のプレイヤーが過去に居た位置に銃を撃っていることになってしまい、狙いを定めるにはラグを念頭に先読み発砲する必要が出てきてしまいます。これを、サーバー上で、ユーザーが銃を発砲した際には、ラグに応じた過去時点での各プレイヤーの位置履歴を参照・検索し、当たり判定を行って、ユーザー側でラグを意識せずに武器を使用できるようにするシステムを指します。弊害として、被攻撃側が攻撃を避けたはずなのに、ネットワーク遅延が激しいプレイヤーの攻撃に被弾しやすいといった問題もありますが、そのメリットの大きさから、概ね受け入れられている方策です。同じサーバーの中の同じ世界をユーザー全員が同じように視点だけを変えて見るというモデルから外れ、クライアントごとに微妙に異なる世界がレンダリングされているというモデルが、今日の支配的なマルチプレイヤーオンラインアクションゲーム環境です。ここまで、FPSゲームのオンラインマルチプレイヤーモードで開発されてきたレイテンシー隠蔽テクニックについて紹介してきました。一方で、欧米のゲームエンジンは、ゲーム開発手法上も大きな発展を遂げてきました。Architecture“は、オブジェクト指向の哲学的なレベルでネットワーク上のゲームモデルを整理した文献としてつとに有名です。4(UE4)用にはそのエッセンスであるレプリケーションのコンセプトを解説した文書のみの公開となっていますが、今日でもその意義は色褪せていません。Engineでは、Sourceでエンティティと呼ばれていたゲーム内の物体はアクターと呼ばれ、ゲームのシーンを構成するレベル内にアクターが居て変数を持っている、という構造となっています。man“(サーバーこそが主人)という有名な文句に象徴されるように、サーバーが持っている情報のみが絶対の信頼性を担保する(authoritative)、という点は当然として、クライアント側が持っている情報は、サーバーが持っている世界の情報の一部を、特定クライアントが感知する必要性のある範囲内のみをパーティショニングして再現(replication)した、いわば影のようなものにすぎない、という視座が語られています。Engineを使ってゲームを開発するユーザーは、UE3まではKismet/UnrealScriptでビジュアルプログラミング/スクリプティングを行い、C++で低レベルコードを書いていました。UE4ではハイレベルのビジュアルプログラミングはBlueprintで、他方(UnrealScriptを排して)リフレクション付きC++でスクリプティングから低レベルのコーディングまでを行い、標準の部品を使う限りでは、属性をon/offするだけで上述のクライアント予測などの機能を手軽に、自動的に利用できるようになっています。Engineの最重要フィーチャーであると思っています。以上が、欧米でのマルチプレイヤーゲームエンジンの簡単な歴史です。2010でのSEGAの講演も参考になります。クライアント側での挙動計算をさらに推し進めた、”Battlefield”のDICEによるFrostbiteエンジンのような近年の方式もあります。4でマルチプレイヤーゲームを開発できれば全て万歳\(^o^)/となれば話が早いのですが、現実的にはなかなかそういうわけにもいかず、様々な大人の事情から、例えば今日のモバイルゲーム開発には、Cocos2d-xもよく用いられます。Cocos2d-xは、無料でオープンソースで、かつそれなりに動作が軽いため、2Dゲーム開発では、日本でも利用例がかなり増えました。最近では、APIの元になったiOSのCocos2Dフレームワークから離れて独自に発展し、Cocosという新ブランドのもとに統合開発環境を構築し始めるなど、活発に発展しています。3D向けのAPIも追加されつつあります。3.3では、サウンド周りのAPIが刷新されるなど、重要な変更もあります。一方で、開発が活発で急速なことによる弊害もあり、バージョンアップでAPIが変わったり、時々変なバグが入っているなんてのは日常茶飯事です。開発の本拠地が中国なので、最新情報を探そうとすると、中国語の掲示板しかなかったりします。2でMac版がWindows版に追い付きました。Studioで開発できて楽しかったのですが、Mac万歳な方々には良好な環境とは言いがたい状態でした。1と比べ、前バージョンと全然違うUIと、駆動するための全然違うコードを必要とし、最近自分で触ってみたところその学習カーブの急さに閉口したので、本記事では後ほど、使い方について簡単に解説します。Cocos2d-xで仮にネットワークゲームを作るとして、Cocos2d-xは薄いフレームワークなので、まだまだ相対的なレベルではUnityなどに比べると機能は少なく、ネットコードやバックエンドサーバーに何を用いればよいか、という問題が生じます。Cloud)などのmBaaSを用いて、モバイルのネットワークゲームを提供する例も増えてきました。そこには留意すべき点があります。それらは、一般に、サーバー側にカスタムロジックをインストールできる機能が提供されていない限り、クライアント側でのデータ改竄の排除や、データセットのクライアント側へのマスクを行えないため、authoritativeにはなれない、ということです。games“に列挙されるような様々な手の込んだチート手法に対し、脆弱であるということを意味します。そのあたりは、ゲームデザインを調整することで対応できる点もありますが、ユーザ間競争要素が高く、かつアプリ内購入機能を重視するゲームデザインを想定する場合は、許容できません。あるmBaaSのモデルとしては、マッチングやランキングといったハイレベルな交流機能と、チャットルーム的なメッセージリレーチャンネルとを提供するというものがありますが、これだけだと、チートに対抗できません。Serverの利用が必要になるということになります。ネットコードについてはどうでしょうか。Cocos2d-xで使える、上記で紹介したようなクライアントサイド予測などの洗練された機能を用意してくれる組み込みライブラリは、残念ながら見つかりませんでした。PhysX、Physics2DはBox2D)のステップ実行がサポートされていないので、物理挙動シミュレーションを1フレーム内で巻き戻したり進めたりということをやりたい場合は、Unityに組み込まれた物理演算エンジンの利用を諦めて自前で挙動をC#で書くか、それが重くて許容できない場合は、C++のネイティブプラグインを作って独自実装を使わざるを得ません。VR社が買収してオープンソース化しましたが、これはこれで低レベルで、クライアントサイド予測などの機能はなく自前で実装する必要があったり、サーバーがあまりフレキシブルではなかったりと一筋縄では行きません。SantaShooterここからは、本記事のためにでっち上げてみたサンプルプログラムSantaShooterを題材に、Cocos2d-xの基本的な使い方を見ていきます。SantaShooterは、2人のサンタクロースが向かい合って上下移動しながら、プレゼントを互いに投げつけ合うという、2Dの2プレイヤーネットワーク対戦ゲームです。proxy.jsで、WebSocketプロキシサーバーを起動クライアントを起動し、プロキシサーバーのIPアドレス:ポートを記入し(無記入のデフォルトは127.0.0.1:31337)、Connectボタンをマウスクリック3つクライアントを起動して接続すると、1番めがサーバー、2番めがプレイヤー1クライアント、3番めがプレイヤー2クライアントとなるプレイヤー1はW/S、プレイヤー2は矢印キーで上下動。相手のエリアをマウスクリックでクリック方向にプレゼントを投げつける。相手に当たると点数加算というものです。Connectボタンを押下しない場合、スタンドアローンで動作します。(Macターゲットのみ、iOS未サポート。v0.10.33ネットワーク機能には、Cocos2d-xに組み込まれているWebSocketを使ってみました。高度なゲームエンジンはUDPベースのプロトコルで通信し、パケットロス対策したり、といったことをやっていますが、今回はその辺りにこだわる余裕は正直ありませんでした。Cocos2d-xのWebSocketにはサーバー用のlisten機能はなさげだったので、node.jsとwsモジュールを使って簡易プロキシサーバーを用意し、そこに接続することで、最初に接続してきたクライアントがサーバーの役目を果たします。アーキテクチャ的には、クライアント-サーバー型のマルチプレイヤーオンラインゲームとなっています。私のPCでは、同じPC上で単純に3つつなげた状態で、ping=150ms程度でした。サーバーは、ハンドシェイク兼pingが済むと、後はひたすらプレイヤー1/2の位置・速度・スコアをクライアントに送り続けます。compression)を行うべきところですが、世界全体の情報量が非常に少ないため、整合性に問題が生じないよう全部のセットを1度に送りつけるという戦略はそれはそれで妥当性があります。クライアントは、クライアントサイド予測を実装しています。クライアント側では自分の挙動とプレゼントの挙動をユーザー操作を受けて直ちに自前で物理演算して表示はしますが、サーバー上での物理挙動が真であり、当たり判定はあくまでサーバー上にしか存在しません。クライアント側の予測とサーバー上のシミュレーション結果にある程度のずれが生じた場合、クライアントにサーバー側の過去の結果を適用して世界を巻き戻し(rewind)、そこから再度クライアント上の操作を再生する(replay)時に、Chipmunk物理エンジンのステップ実行を行います(step関数に負の値を与えると動作を巻き戻せるのでこれはこれで面白いです)。物理エンジン自体を先に進めると、プレイヤーのみならず世界全体が早送りされてしまうので、プレゼントボックスは早送り前に情報を保存し、早送り後に復帰させています。物理演算は固定フレームレートで実行できるとサーバー・クライアント間の同期を取りやすくシミュレーション結果に差異が生じにくいですが、今回は物理エンジンのシミュレーションを可変フレームレートの1フレーム内で毎回、常に1/60秒分進め、クライアントから送るフレームシーケンス番号を使ってクライアントとサーバー間で歩調を合わせる行進方式としています。コード上は、GameScene::rewindAndReplayClientWorldState関数に実装しています。60.0f);}restoreGiftboxesProperties();}}}サーバー上では、上述のラグ補償を簡易的に実装し、攻撃を行うと、攻撃中は、対象ユーザーの過去の位置にヒットボックスが現れ、対象ユーザーに追随動作します。通信パケットは、デバッグしやすいように、Cocos2d-xに組み込まれているRapidJSONを用いて、JSONにしました。Studioのcsbフォーマットのシリアライズ/デシリアライズ用にGoogleのFlatBuffersが組み込まれているので、それを用いることもできるかもしれません。RC0で読み込めず、エラーメッセージ無しで落ちるため、焦りました。RapidJSONについても、読み込む型が違ったりするとassertに引っかかるので、実際に使う場合は、マクロでRAPIDJSON_ASSERTをオーバーライドし、例外を投げるなどの自前のコードを仕込んでおくのを推奨します。サーバーとクライアントのコードは渾然一体で書かれていますが、物理演算や通信部を共有できるのが良いくらいで、本来は共有部分以外は分離して書くべきです。今回はプレイヤー1とプレイヤー2をハードコードしていますので、かえってコードに無駄が生じてしまいました。リファクタリングするならば、任意の数のクライアントをサポートできるように、アクターにIDを振ってコントロールできるようにしておくべきです。Cocos2d-xを使うからには、C++1xをこねくり回すのが個人的にはなかなか楽しみではあります。JSONは、不定形なデータを気楽に投げ込むためのバッグでありシンクとして利用できることを期待して使っているわけですが、JavaScript等と違って、C++は当然ながら静的型システムなので、気楽に使うにはやや扱いづらいところもあります。完全にダイナミックな処理を書くならともかく、ソースコード内に似たようなRPC関数風スタブ群を手書きで構成する場合に、引数の型や数がまちまちだったりすると、いちいちRapidJSONの手続き的コードをコピペするのも見苦しいところです。Templatesを用いてみました。std::string(sb.GetString());}createMessage関数は、先頭3つの引数は、その関数の命令コードや、ディスパッチ元など、定型的なものを指定しますが、4つ目以降は、JSON上の”a0′′、”a1′′、”a2′′...というキーで、整数や文字列など、引数の型に応じて適切なRapidJSONのAPIを呼んで値を格納してくれます。std::tupleでも似たようなことはできますが、std::tupleはイテレーターが無いため、ここで指定されたリスト要素に対して順にaddKV関数の処理を適用するために、テンプレートエイリアスを用いて宣言した配列の初期化リストが左から順に初期化されるという性質と、複合式で返り値voidの関数含め左から順に評価(結果は無視)された上で右端の結果が返されるという性質とを用いています。10年前にはマクロによる型リストを用いたC++テンプレートメタプログラミングに熱中したものですが、C++1xの時代になっても、いまだにこういう変なテクニックの出番があるという事実に戦慄せざるを得ません。Fileを選択し、Nodeを作成すると、Canvas上にボタンなどのControlをドラッグ&ドロップして配置できるようになります。ちなみに、Cocos2d-x的には、Layerはインターフェイスとしては残りますが、今後は廃止され、Nodeのみが用いられるようになります。Nodeは現在Layerのすべての機能をサポートしています。Studioを使って作成できます。Studioに内蔵されています。FileからSpriteSheetを選択し、csiファイルを作成Canvas上のcsiファイルに、Resourcesからスプライトシートに含める画像を複数選択し、ドラッグ&ドロップ以上で、選択した複数画像を含むスプライトシートが作成されます。Publishするとplistが生成され、SpriteFrameCacheを使って読み込むことができます。目のアイコンで切り替えるものと勘違いしていたので、気付くまでここはハマりましたVisibleチェックボックスを切り替えて同時に1つの画像のみ表示されるようにしていけば、コマ送りのスプライトアニメーションを構成できます他のスケールなどのプロパティについても同様にタイムライン上で変化させていくことができます出来上がったら、保存されたcsdファイルからcsbファイルを生成するために、publishを実行すると、.cfg内で指定されたPublishDirectory内にcsbファイルが吐かれ、CSLoader::createNodeやCSLoader::createTimelineを使って、csbファイルからUI部品ノードやcocostudio::timeline::ActionTimelineアニメーションを読み込めるようになります。Cocos2d-x自体は、変わった使い方はしていません。NodeをSceneにAddChildし、要らなくなったらNode自身のremoveFromParentを呼び出してautoreleaseに任せる、というだけです。今回は挙動のコントロールに物理演算を用いましたが、MOVE_WITH_PHYSICSマクロ周辺に、物理演算を使わずActionで等速運動をさせる書き方も書きましたので、参考にしてみてください。PhysicsBodyでコリジョンの対象を規定するsetCategoryBitmask、setCollisionBitmask、setContactTestBitmaskはこれまたドキュメントがソースコード中にしか無く、また使い方もわかりにくいので、デバッガでステップ実行でもしながら制御フローを追い、ソースコードそのものを読んだほうが理解が早いかもしれません。Cocos2d-xは最終的には「ソース読め」に行き着いてしまうので、そこが辛くも有り難いところです。2015年ここでのサンプルはPC上での実験に留まりますが、対象をモバイルデバイスとした場合、変動するping値にどう対処するかなど、頭の痛い問題が現れてくるのもまた事実で、ネットワークプログラミングに対してクリアな回答というものはまだ世に存在しません。Systemといった、サーバーサイドで全ての演算とレンダリングを行い、動画をクライアントへストリーミングするというソリューションもありますが、モバイル回線に降りてくるにはまだ時間がかかりそうですし、アクションゲームに望ましい低レイテンシーに耐えうるものとなりうるかは未知数です。一方で、Cocos2d-xはオープンソースのフレームワークで、日進月歩の様相を見せており、いわば終わらない祭り状態です。2015年、どんな愉快なことになっているか、今から楽しみです。Reliabilityチームの「いわなちゃん」さんによるVarnishのお話です。