こちらは、2019年6月9日に公開された以下のドキュメント(執筆者:Cem Demir氏)を翻訳したものとなります。
The journey of Multiplayer FPS game with PlayCanvas
---
本稿では、MiniRoyale.ioをどのように開発したのかについて記載します。MiniRoyaleは、バトル・ロワイアルモードのあるマルチプレイヤーFPSシューティングゲームです。
このゲームは2019年3月4日にリリースされ、現在までのユニークプレイヤー数は63万人に達しています。好調な状態が続いており、継続して新機能をアップデートしています。
このゲームはDiscordにコミュニティがあり、新機能の要望が寄せられたり、バグの報告が上げられたりと大変有益なコミュニティとなっています。コミュティなしでは、このゲームは現在のような姿にはなっていなかったと思います。コミュティでのサポートに感謝いたします。
ゲームのユーザーは日次で1万人にのぼり、同時接続オンラインユーザー数は100~200となっています。
ゲームには2つの異なるマップと、マップを含む3つの異なるシーンがあります。具体的には、ログイン画面、map1シーン(North cityマップ)とmap2シーン (South cityマップ)があります。
以下は、ログイン画面のスクリーンショットです:
ご覧のとおり、ここには2D画面があり、これがPlayCanvasのもっとも優れた特徴です。エディタのこの機能を使うと素晴らしいUIを作成できます。HTMLでは実現できません。UIはキャンバス内でレンダリングされ、マウスインタラクションの動作はすべて持続されます!最新かつ最適なDOM方式に類似しています。
背景シーンは3Dで、マッチメイキングを待つ間にアニメーションが表示されます。
このシーンには、DOM入力エレメントの作成を許可するスクリプトがあります。PlayCanvasではまだ入力やフィールドの選択がサポートされていないため、このスクリプトが必要でした。このスクリプトの作成によって、ユーザーはユーザー名を入力できるようになりました。
以下は、入力スクリプトのスクリーンショットです。このスクリプトによってDOMエレメントを作成でき、またエレメントの位置とサイズを設定しました。また、このエレメントを後でスクリプト上で使用し、選択するためのIDを定義しました。このエレメントにはオプションを追加できます。
ご覧のとおり、入力スクリプトにはPlayCanvasエディタで機能する複数のattributeがあります。これもまた、このエディタの優れた機能です。「attributes.add」機能を使用して、属性フィールドを作成できます。以下の入力スクリプトのスクリーンショットでは、この入力スクリプトがPlayCanvasエディタ内でどのようにフィールドを作成するかを示しています。
入力スクリプトは以下にアップロードしました:
https://gist.github.com/devcem/224608fd8fc2a988665257116cb629ce
「Join Match」ボタンを押すと、他のシーンを読み込む機能が呼ばれます。ただし、その前にlocalStorageに変数が保存され、シーンを読み込んだ際に正しいサーバーIPに接続できるようになります。また、これらの変数にはユーザーの嗜好が記録されており、次回のログイン時に使用されます。
マップが読み込まれると、各マップ上にはオブジェクトがあり、このオブジェクトによってすべてのネットワーク接続が作成されます。オブジェクトにはゲームの実行やオーバーレイ、プレイヤーのための多くの属性があります。以下がそのスクリーンショットです:
はじめにマップ選択エンティティが表示され、ユーザーはデプロイ位置を選択できます。これも2Dのシーンです。
ロケーションはstaticで、3Dの世界で位置をスポーンするために接続されています。このボタンをクリックすると、デプロイ位置はネットワークスクリプトに送信され、すべてのユーザーにブロードキャストされます。ユーザーの位置についてサーバーからシグナルがある場合には、ネットワークスクリプトはこのボタンを非有効化します。これは、ネットワークスクリプトがすべての権威を所有しているためです。以下は、位置選択ボタンのスクリーンショットです:
フラグは配列型の属性に保存されます。
また、ヘリコプターエンティティが有効化されているため、都市にジャンプする前にクールなアニメーションが表示されます。
ヘリコプターにも、ローターを回転させるためにスクリプトを使用しました。このような処理にアニメーションは不要で、スクリプトやスクリプトの最新機能によって処理されます。
もう1点、説明しておきたい秀逸な機能があります。それは境界です。お分かりのとおり、境界はネットワークスクリプトに接続されています。
ただし、ライトなのです!私はスポットライトを使用し、範囲と角度を定義して境界を円のように作成しました。Y軸の位置は500で、チェックするごとにマップに近づきます。この位置変更によってCS:GOのデスゾーンモードのような視覚的な効果が生まれます。
異なる位置での2つの画像を以下に示します。
円距離機能によって、円の中にいるかどうかの確認をおこなっています。ゾーン関連の処理は、X軸上およびZ軸上でランダムに変化する位置でおこなうこともできます。
以上でゲームインターフェースとその変更をともなうプレイヤーエンティティが有効化されたので、ゲームのプレイを開始できます。
このゲームプロジェクトが始動した際には、PlaycanvasのFPSテンプレートで作業を開始しました。テンプレートへのリンクは以下です:
https://developer.playcanvas.com/en/tutorials/first-person-movement/
このテンプレート上には、あらゆるものを構築できます。テンプレートには、マウスロッキングやキーダウン、キーアップ、コリジョン、物理など必要なものすべてが含まれています。
先に述べたとおり、ネットワークスクリプトはすべてを実行します。スクリプトは他のプレイヤー用に敵エンティティをクローンし、スクリプトを有効化します。これによって、敵の動作をエミュレートできるようになります。
敵エンティティは戦士モデルを含むオブジェクトで武器を所持しています。最初に武器は非有効化され、ユーザーがルートロケーションから武器を取得するとネットワークスクリプトがこのエンティティエレメント内で武器を有効化します。こうして、ルートロケーションにひもづけられた武器のうち1つのみが表示されます。
ノードツリー内で戦士モデルの手を探し出すためにfindByNameを使用し、findByNameに武器モデルをひもづけました。
また、FPSインターフェースを提供するプレイヤーコントロールもあります。このプレイヤーコントロールには手のみがあり、体の残りの部分は必要ありません。この手のモデルは敵モデルよりも詳細に設定されています。FPSでは、より近いモデルについて詳細な設定を保持することが重要なためです。
プレイヤーモデルにも同様の構造があり、武器を手で隠したり、手に持ったりすることが可能です。この構造にも、体の腕や武器、手の動きがひもづけられています。
また、様々な状況に使用できるよう多くのサウンドが設定されています。
キーダウン、マウスの位置変更などのすべてのアクションがサーバーに転送されます。そして複数の計算の後に、アクションは他のプレイヤーのクライアント上の敵としてレンダリングされます。
より複雑なため、ネットワーキングについてはここでは詳述しません。別の投稿でご説明しようと思います。
もう1つ、述べておきたいことがあります。それはマップです。マップは巨大な画像であり、マップの位置はプレイヤーのX座標、Z座標に関連しています。
ただし、コンテナでの表示にはマスク機能を使用しました。以下は、マップがどのように表示されるかを正確に示す画像です。
マスク機能を非有効化すると、マップと境界の全体が表示されます。
家モデルにはドアや窓ガラスがありません。これらはPlayCanvasのエンティティ構造に含まれています。
家用にプロトタイプを1つ作成し、クローンしました。これらのクローンはすべて同じスクリプトと構造を持ちます。
ドアや窓ガラスにはそれぞれ固有のスクリプトがあります。他の部分についても同様です。
ネットワークサイドでは、単純にガイド値を使用しています。窓ガラスやドアにはすべて、固有のguid値があります。
また、guid値はエディタ内でマップを作成する際に生成されます。ドアを開く、窓ガラスを割るなどのguid値やステートIDは、ネットワーク上で送信されます。こうして窓ガラスが割れたりドアが開いたりすると、すべてのプレイヤーに見えるようになります。他のクライアントに情報が到達すると、ネットワークエンティティはguidでオブジェクトを見つけ、スクリプト上で同じ機能をトリガーします。
PlayCanvasエディタがなければ、このゲームの実現は不可能でした。このプロジェクトでは私達は2人の友人と同時に作業し、彼らがマップをデザインしている間に私はコーディングをおこなっていました。また、アップロードやデプロイなしでテストを実施することができました。
PlayCanvasチームの尽力に感謝いたします。
ネットワーキング、最適化、アカウントシステム、リーダーボードについては別の機会に共有します。
コメント
0件のコメント
サインインしてコメントを残してください。