ローグライク風アクションオンラインゲームを制作しながら気づいたことやタメになった記事のまとめです。運用時の規模が10人から100人ほどの規模を想定しています。小規模オンラインゲームにおいて考慮しなければならない点をひと通りまとめてみました。
オンラインゲームの概要
オンラインゲームってなんぞや
オンラインゲームはざっくり言えば、他の端末やPCとデータをやり取りしながら進行するゲームです。
「こんなん当たり前やろ」と思うかもしれませんね。ですがここを考慮しているのかどうかで色々変わってくるよ、というのが今回の記事の趣旨です。
オンラインゲーム制作のざっくりしたフロー
私がとっているスタイルなので、既にオンラインゲーム制作のノウハウがあったり、複数人で制作を行う場合はこの限りではありません。
制作するオンラインゲームの種類を定義しておく
個人制作であってもMMORPGなどそれなりの制作規模となると指針は決めておいたほうが作りやすいです。制作の方針を固めておくためにも自分が制作するゲームがどの分野に属するのか見極めておくのをオススメします。
※定義の内訳については「ネットゲームの裏で何が起こっているのか。ネットワークエンジニアから見た,ゲームデザインの大原則」を参考にしました。
ざっくりと上記の記事を元にオンラインゲームの種類を分類したのが以下になります。
上記の定義による、「完全同期型/キー入力同期方式」「完全同期型/コマンド入力同期方式」「非同期型/サーバー集中処理型」がMMORPGにおいて全く不要かと言われると実際は違います。あくまで方針と考えてください。実際は作る処理によって変わってくるので。
とりあえずオンラインで動かそう
サーバと連携する
私が制作しているゲームは毎秒30回処理が走っています。30FPSですね。とりあえず何も考えずにサーバへ処理を移していくのですが、その前に「何を」サーバで動かすのかを洗い出しておきます。あと、サーバでループ処理も作らないといけないですね。
オンラインで動くようになってきたなーと感じてくる頃にはこんな形になってくると思います。一部正確でない書き方がありますがなんとなく分かってもらえたら大丈夫だと思います。
図を見比べて見ると分かるかと思いますが、実質追加した処理はほとんどありません。メッセージの送受信処理くらいです。移植に近いですね。なので、移植しやすいようにオブジェクト指向で作っておくと時間をかけずに制作を進められます。
チートや不正・迷惑行為を行うプレイヤーを考慮する
チートや不正を行う方法はたくさんあります。といっても、不正を行わせないようにしようにも、どうやって不正が行われるのかを知らないと対処法が分からないと思うのでざっくり説明しておきます。
特にJavaScriptを用いたオンラインゲームですと、ブラウザという実行環境がありますのでややこしくなります。例えば、ブラウザの処理を1万倍の速度で実行するようなクラックツールを使われるとどうしようもない部分もあったりするワケです。サーバがクライアントからあるメッセージを受け取ったら、即座にデータを返すような処理を”何も考えずに”作っていたら、あっという間にサーバがパンクして停止してしまうでしょうね。
ではそれを防ぐために、実行速度がミリ秒単位で異常だと検知させるようにサーバで処理を作ったとします。でもそれはユーザが意図せず実行速度が遅かったり、ブラウザのバグで早くなったりしたら不満しか出ません。
だからと言って、「ランキング上位者に賞金を与えよう」というイベントを行ったら必要かもしれません。ケースバイケースなのでじっくり考える必要があります。
そこで、厳密では無いにしろサーバ側でガードを設けておく必要が出てきます。
だからと言ってノーガードは嫌だ
ここで当記事の本題に入っていきます。サーバでガードを設けるといっても私はそんなに難しいことはしていません。必要に応じてよりリッチな処理にしていけばいいんじゃないかなと思ってます。
リッチではなくてもこれさえ作っておけば、メッセージ送信のタスクが不正によって異常に増える心配はしなくてよさそうです。メッセージ受信のタスク増大も心配ならリッチにしていきます。
次はクライアントサイドのプログラムを改造されてしまうことへの対処です。送信されるデータ(パケット)の不正な改変への対処とかぶってます。
リッチにすればするほどサーバの負担は大きくなります。私は専門家ではないので更に詳細なテクニックは分かりません。シンプルに(極端に)言い表すならば、クライアントに依存するのか、サーバに依存するのか、その両極の間でのトレードオフを探す必要があることは確かです。「非同期型/サーバー集中処理型」と「非同期型/クライアント分散処理型」の間で良さげな方法を取ることになります。
不正なユーザを排除したいなら、「非同期型/サーバー集中処理型」を目指してプログラム+パケットの暗号化しとけばいいんじゃないかとも思ったのですけど、当記事のタイトル通り、サーバのリソース(主にCPU)が食いつぶされてしまうのです。節約!
見事にとんぼ返りしたアプリケーション設計
今後変更していく可能性もありますが、現在の相関は以下のようになっています。
見事にクライアント依存に戻っています。作りながら途中で気づいたので仕方ないですけどね。結局、サーバのマシンパワーでゴリ押し出来るほどポケットマネーから出す予定も無かったのでこうなりました。
※ ただし、サーバのマシンパワーでゴリ押しするにも限界はあります。効果的なサーバのスケールについては「サーバ/インフラを支える技術」が参考になります。
※ どうせなので良さそうな本と読んだ本を一緒に紹介しておきます。
サーバ/インフラを支える技術 ‾スケーラビリティ、ハイパフォーマンス、省力運用 | ||
---|---|---|
サーバのスケールが必要になって来るほどアクセス数が増えたら、とりあえずこの本読んどけ的な名著のようです。読み物としても面白かったですし、サーバの数取り敢えず増やせばいいんだろ?くらいの認識しか無い私にとっては眼から鱗でした。サーバやOS周りの概要を理解する足掛けになると思います。 | 大規模サービス技術入門 ―データ構造、メモリ、OS、DB、サーバ/インフラ | |
「サーバ/インフラを支える技術」が座学のような概要の書籍だとしたら、こちらはより実践的な内容となっています。記述されている内容自体はほとんど似たようなものですが、コードが多く記載されているので試しながら読みたい方は、「サーバ/インフラを支える技術」で概要を理解した後に読むといい感じだと思います。 | オンラインゲームを支える技術 --壮大なプレイ空間の舞台裏 | |
まだ読んでないので、読了したら書き直します。 |
このアプリケーション設計の変更を図で見ると分かるのですが、「非同期型/サーバー集中処理型」と「非同期型/クライアント分散処理型」の境目って、ただの配分なんですよね。この部分は「非同期型/サーバー集中処理型」だけどこっちは「非同期型/クライアント分散処理型」だ、って感じになります。完全にFPS系のゲームでなくても、遠距離攻撃を実装したらFPSに必要な処理は必要になってくる訳ですし。
ちなみにですが、JavaScriptの性質上、ユーザからコードが丸見えなのですけど特に対策はやっていません。クライアントを信頼しきっています。サーバに依存して通信頻度が増えるとiPhone4Sの加熱が止まらなかったというのもあります。このままリッチにしていくならば、スマートフォン用とPC用で処理を分けていく方向になるんかな?スマートフォンでプログラム改造されたら終わりますけどね。リッチにしていく前提で構成を見直すならば、JavaScriptという選択は間違っているということかもしれません。
少し言い訳をすると、トレードオフの微調整をしながらテストを繰り返すので、サーバとクライアントのプログラム言語が同じだと制作時間を短縮できます。ここはメリットでした。
リソースや帯域を節約する
前置きが長かった割に、節約する方法は他人任せでいきます。参考になる記事は以下です。
「ロブロブラボ – MMOの作り方」
「エイバース – ゲーム製作講座」
「エイバース – オンラインRPGの作り方」(特にプログラミングアーキテクチャ)
結局私は大した対策を特にやってません。登録ユーザ数が増えてデータ検索を高速化しないといけないとか、サーバが落ちたりしたらアップデートしようかなと思ってます。サーバのスケールは最後の手段ですね。オンラインゲームのアーキテクトの勉強を兼ねてるので、そんな事態が起きたら嬉しいなぁ。
※ 「エイバース – ゲーム製作講座」にて一部不正確な情報が載っていましたので、取り消し線をつけました。