「空島大乱闘」のオンラインの技術的なこと その4

伝説のマニアです♪U・ω・U

前回は、キー操作の同期化について概要を説明しました。今回は、キャラクターイベントの同期化について説明したいと思います。

【連載記事一覧】
「空島大乱闘」のオンラインの技術的なこと その3
「空島大乱闘」のオンラインの技術的なこと その2
「空島大乱闘」のオンラインの技術的なこと その1



【イベント同期化の重要性】
イベント処理は、出来る限り正確に同期化する
前回説明した、キー操作の同期化処理については、ある程度妥協した形で同期化する方法を取っていました。各プレイヤーから見た、他のプレイヤーの見た目が一致しない事が頻繁に起こるというものです。

しかし、キー操作と違って、キャラクターのイベント処理は重要な要素である事が多いため、出来る限り正確に同期化したい、と思いました。

ここで言うキャラクターのイベントとは、「プレイヤーが攻撃した」とか「プレイヤーがダメージを受けた」、「プレイヤーが死んだ」という処理の事です。



【イベントとして送信する情報】
空島大乱闘では、イベント情報として、以下の情報を他のプレイヤーへ送信しています。

・攻撃した・・・・・・(当たっていなくても)パンチ等を行った
・武器を取った・・・・キャラ1の落ちている武器を拾う処理(※武器取得の流れを後述します)
・武器を落とした・・・キャラ1の持っている武器を落とす処理
・必殺技を出した・・・キャラ2の(当たっていなくても)必殺技を行った
・ダメージを受けた・・敵から攻撃されて、ダメージを受けた(一瞬怯む動作)
・吹っ飛ばされた・・・敵から攻撃されて、ぶっ飛ばされる処理
・落ちた・・・・・・・空島から落下した
・ダウンした・・・・・ぶっ飛ばされた後にダウンした(必ずダウンするようになっています)
・死んだ・・・・・・・ヒットポイントが0となり、死んでしまった
・コインを取った・・・落ちているコインを取得した

イベント情報パケットについて
上記のイベントが発生した場合は、そのイベントを同期化するため、イベント情報パケットを送信する事になります。空島大乱闘では、イベント情報パケットは二種類あります。

一つ目は、プレイヤーの操作から発生したイベントで、「攻撃した」や「必殺技を出した」の処理になります。そのさいに送っている情報は、以下の通りです。

・プレイヤーID・・・・・ゲームサーバーより割り振られたID
・プレイヤー位置情報・・プレイヤーのワールド座標位置値
・イベントタイプ・・・・「攻撃した」「必殺技を出した」等の種類

このパケットを受信した端末では、「プレイヤー位置情報」へプレイヤーを強制移動し、「イベントタイプ」で指定されたイベントを必ず行います。

イベントを行ったプレイヤーがどの位置にいようとも、強制的にプレイヤーの位置を移動させ、今プレイヤーがどのような状況であったとしても、強制的にイベントタイプで指定された動作を行うようにしています(一部例外はありますが、稀なケースなのでここでは省きます)。

キー操作の場合だと、プレイヤーの位置はトゥイーンにより移動させていましたが、イベント処理は強制移動となっています。この辺は悩み所でしたが(ぶっちゃけどっちでもいいのですが)、キー操作よりも重要ということでこのようにしました。

二つ目は、プレイヤーが他から受けるイベントで、「ダメージを受けた」や「死んだ」、「コインを取得した」の処理になります。その際に送っている情報は、以下の通りです。

・プレイヤーID・・・・・ゲームサーバーより割り振られたID
・プレイヤー位置情報・・プレイヤーのワールド座標位置値
・イベントタイプ・・・・「ダメージを受けた」や「死んだ」等の種類
・パラメーター1・・・・4バイトの浮動小数点数
・パラメーター2・・・・2バイトの整数型

二つ目のイベントも、強制位置移動と、強制イベント処理を行っていることは、一つ目と変わりありません。

ただ、「どのくらい吹っ飛ばされたか」や「どのコインを取得したのか」は、イベントタイプ情報だけでは分かりません。なので、パラメーターを追加して汎用的に使うことで、情報を同期しています。例えば、以下のような情報を送っています。

→ダメージを受けて、吹っ飛ばされた場合
・プレイヤーID・・・・・ゲームサーバーより割り振られたID
・プレイヤー位置情報・・吹っ飛ばされた時のプレイヤーのワールド座標位置値
・イベントタイプ・・・・吹っ飛ばされた
・パラメーター1・・・・吹っ飛ぶキャラのrigidbody2D.velocityへ入れる値(x軸のみです)
・パラメーター2・・・・攻撃主(敵キャラ)のID

→コインを取得した場合
・プレイヤーID・・・・・ゲームサーバーより割り振られたID
・プレイヤー位置情報・・コイン取得時のプレイヤーのワールド座標位置値
・イベントタイプ・・・・コインを取った
・パラメーター1・・・・未使用
・パラメーター2・・・・コインのID

※因みに、なぜ攻撃主のIDが必要かというと、攻撃主から発する効果音を鳴らす必要があるからです。敵キャラによって、殴られた時の効果音が違うので、「どの敵キャラに殴られたか」という情報が必要になっています。

ダメージ処理について
上記のパケット情報を見てみると、どれだけのダメージを受けたか、という情報を送っていないことに気づきます。そうです、プレイヤーのダメージ値情報は同期化していないのです。

空等大乱闘では、協力プレイであるというのと、簡易的なダメージ処理システム(FPSでよくあるような、ダメージを一度受けても、一定時間ダメージを受けなければ回復するというもの)であるため、今自分のヒットポイントがどれだけ残っているか、というのは重要ですが、他のプレイヤーのヒットポイントが残りどれだけであるか、というのはあまり重要ではありません。

なので、プレイヤーが死んだのか、死んでいないのか、が分かればいいのです。むしろ、他のプレイヤーのクラスのメンバー変数として、ヒットポイント値を保持してもいませんw

実装としては、「is_death」という死んだか死んでいないかどうかの判定用の変数(bool)だけを用意し、「プレイヤーが死んだ」というイベントを受け取るとフラグをonにしているだけ、ということになります。

協力プレイということや、簡易なダメージシステムにより、この実装方法が成り立っているかと思います。これが対戦型や、複雑なダメージシステムだと成り立たないかもしれません。



【武器取得処理】
空島大乱闘では、上述のように、キャラクターイベント処理は、結構単純な情報で同期化されていることが分かると思います。

しかし、武器取得イベントについては単純にはいきません。

落ちている武器を取得出来るのは、自分だけではなく、他のプレイヤーも取得することが出来るため、武器取得イベントが被る事が考えられるからです。

例えば、プレイヤーAとプレイヤーBが、落ちている同じ武器を同時に取得するイベントを発生させた場合に、お互いに自分の端末では取得成功しているが、相手方(Aから見るとB、Bから見るとA)の武器取得情報をまだ受信していない場合です。

この場合、落ちている武器を自分が取ったはずなのに、他のプレイヤーも同じ武器を取った、というイベントを受ける事となってしまいます。


これを回避するため、空島大乱闘では、ゲームサーバーを介して以下の処理手順により同期化を行っています。

→武器取得処理が成功するまでの一連の流れ
(1)プレイヤーより、武器取得リクエストをゲームサーバーへ送信する
(2)ゲームサーバーより、武器取得リクエストが成功した、というパケットをプレイヤーに送信する
(3)プレイヤーは、武器取得成功を受信すると、実際に武器を取得する処理に入る
(4)プレイヤーより、完全に武器取得処理が成功したら、終わった事をサーバーへ送信する

通常通りうまくいけば、上の処理で武器取得は成功します。しかし、以下の場合だと武器取得処理は失敗します。

・パターン1
(1)〜(3)の間に、武器取得リクエストを送信したプレイヤーが敵からの攻撃を受ける等して失敗した場合
  →この場合、(4)で武器取得が失敗した事をサーバーへ伝える

・パターン2
(1)の処理が他のプレイヤーと被った場合
  →この場合、サーバー側へ最初にリクエストパケットを到達させたプレイヤーが勝ちですw
  →サーバーから、武器取得成功パケットと、武器取得失敗パケットを、それぞれプレイヤーへ送信します

※上記パターンは代表例で、実際のプログラムはもっと複雑です

基本的には、(1)でリクエストを受けたサーバーは、当該武器をロックし、以後他のリクエストが来てもこれを受け付けません。その後、最終的に(4)で成功が来ると、そのままロック、(4)で失敗が来ると、再度ロックを解除し受付できるようにしています。



【コイン取得処理】
武器取得処理についてはそれなりにちゃんと同期化していますが、コイン取得処理は、テキトーです。

ぶっちゃけ、コイン取得はイベント被りが可能となっていますw

プレイヤーAとプレイヤーBで同じコインを同時に取得した場合、両方ともコインを取得した事になりますw

この辺は、特にコインの取得処理が被っても問題はない、ということで妥協しています♪U・ω・U



【まとめ】
今回は、キャラクターイベントの同期化について説明していきましたが、言葉だけで説明しているため、ちょっと(結構)分かりにくいかもしれません。

私に図とか絵を描くセンスがあれば、それを駆使しまくって説明したいと思うところですが、あいにく皆無です(日本語もアレですが)。

。。。とりあえず、キャラクターのイベントは基本的に重要なのでしっかり同期化していますが、(コイン取得処理のような)重要ではない処理は同期化をある程度妥協していく、という方法で実装しています!!
テーマ: Unityゲーム制作 | ジャンル: コンピュータ

コメント

コメントの投稿


管理者にだけ表示を許可する