見出し画像

モバイルゲームのガチャやログインボーナス実装について

前置き

最近ではゲーム開発においてネットワークの要素は欠かせない要素になってきています。

一言にネットワークの要素といっても様々な要素があります。
・DLCや配信による追加コンテンツ対応
・ユーザーのセーブデータ管理
・ガチャやログインボーナス等の処理
・プラットフォームサービスやSNS等外部サービスとの連携
・サービス運営でお客様サポート等を行うために必要な諸々の話
・ネットワークを通じたマルチプレイ
等々…

今回はガチャやログインボーナスの詳細を追っていきたいと思います。
配信によるコンテンツ対応ユーザーのセーブデータ管理も併せて見ていただけたら幸いです。

ガチャの処理

画像1

大まかな流れとしては、上記の画像のようにリクエストが飛んできて処理するわけですが…

もう少し詳しく見ていきましょう。
ここでのガチャでは、「石を消費して、ランダムにキャラクターカードを獲得する」という事にします。

1.クライアントからサーバーに対してガチャを引く通信をします。
しかし、ガチャは複数種類あることが通常です。
サーバーと通信を行う際に、どのガチャであるかを表す「gacha_id」もセットで送信し、サーバーにガチャを引きたいという事」を伝えます。
ここでは user_idが1の人が、 期間限定のガチャ gacha_id 100番を引いた事にしましょう。

2-1.まずAPIサーバーは DBサーバーからgacha_id が100番のガチャに関する情報を取得してきます。

DBサーバー上では、ガチャの情報は下記のような形であるとしましょう。

画像2

「SELECT * from gacha_info WHERE gacha_id=100」というようなSQLクエリを発行する事でgacha_idが100に関するデータだけをDBサーバーから取得します。

gacha_id 100番は期間限定のガチャで石を3つ使用して引くガチャでした。
なので、対象ユーザーの石を減らす処理をする必要があります。

2-2.次に、ユーザーの石を消費します。
そのために、APIサーバーから、userの石の所持情報をDBサーバーから取得してきます。

下記のような形でDBサーバー上ではユーザーのデータがあるとしましょう。

画像3

「SELECT * from user_inventry WHERE user_id=1」このような感じのSQLクエリーでDBサーバーから情報を取得してきます。
uesr_id 1の人は無料枠の石を1つ、有料枠の石を14つ持っていました。
石を三つ消費するので無料枠の石を0個、有料枠の石を12個にUpdate(更新)します。

「UPDATE user_inventry set free_stone=0,premium_stone=12 WHERE user_id=100」このようなSQLクエリーを発行してDBサーバー上のデータを押印します。

画像4

2-3. 次に抽選処理をしましょう。
そのためにAPIアーバーは、gacha_id 100番のガチャ抽選テーブルをDBサーバーから取り寄せます。

DBサーバー上では、ガチャの抽選は下記のような形であるとしましょう。

画像5

ここの gacha_id 100の情報だけ欲しいので、
「SELECT * from gacha_lot_table WHERE gacha_id=100」というようなクエリを発行する事でgacha_idが100に関するデータだけをDBサーバーから取得します。

この取り寄せた結果からAPIサーバー側で抽選処理を行います。
ここでわかるのが、gacha_id 100で当たるのは下記のとおりです
 - card_id 5=> 確率 9/30 
 - card_id 6=> 確率 9/30
 - card_id 7=> 確率 9/30
 - card_id 8=> 確率 3/30
※ 母数の30は 9+9+9+3で合計30なので、30です。

抽選の結果、ここでは card_idが7の情報が当たったとしましょう。

2-4.user_id 1の人にcard_id 7を付与する必要があります。

カードをユーザーに付与するために、ユーザーの所持カードリストにuser_idが1でcard_idが8となるデータをInsert(挿入)します。

例えば、こんな感じのSQLクエリをDBに発行する事でデータが挿入されます。
「Insert into user_card_inventry (user_id,card_id,exp,date,delete_flag) VALUES (1,8,0,"2020/8/15 22:00",0)」

画像6

これでキャラクターカードの付与が完了しました

2-5.最後に当たったのが card_id 3である事、消費後の石の状態をクライアントに返します。

このカードID 3が当たりましたよ、ガチャ後の石の数はこれですというのをAPIサーバーからクライアントに返します。

3.最後にクライアントはサーバーから受け取った石の数を反映し、受け取ったcard_idで演出処理を行い、メモリ内のカード所持リストに追加します。

そしてクライアントはサーバーから受け取った結果を元に表示演出等を行うわけです。


※実際の商用サービスでは、DBに都度アクセスすると負荷になるので、 memcachedなどのキャッシュの機構を取り入れているかとは思います・・・が、話がややこしくなるので割愛しています。

10連打とSR確定などもあるのでガチャのロジックは実際はもう少し複雑なのですが…ざっとするとこのような形になっています。

トランザクションという概念

このサーバーで 行った動作ですが、もしも抽選の過程で処理に問題が発生してしまったらどうなってしまうでしょうか?プログラムに不備があるという以外にも突然APIサーバーがシャットダウンしてしまうとか、DBサーバーとの接続が切れてしまうとかそういったトラブルが起きない保証はありません。

不測の事態ではあるのですが、こういう事も想定しなければなりません。

そして、この不測の事態が発生すると何が起きるのか…。そう、石が消費だけされて返ってこないという事件になってしまいます。

そこで出てくるのがトランザクションという考え方です。
データベースの一連の処理を一つの塊として扱うという考え方です。

今回の場合、下記の二ステップです。
1.user_inventryにある user_id 1のデータをUpdateして石の量を変化させる
2.user_card_inventryに user_id1, card_id 8のデータをInsertする

この二つともが成功したときにコミットし、なにか問題があった時はロールバックするという風にして、1,2の間で問題があった場合には何もデータが置き換えられないで済むわけです。

※筆者はそれでも怖かったので、基本的にユーザーが不利益になる処理は最後に行うようにしていました。

ログインボーナスについて

ここまでで大分長くなってしまいましたがログインボーナスも簡単に触れておきましょう。

ログインボーナスは、日付をまたいでゲームのトップ画面等に遷移したときにアイテムが付与されるものです。
これも結局は…
1.クライアントから通信を行う
2.受け取ったサーバー内で判定しアイテム付与を行い、付与したアイテムについての情報等をクライアントに送る
3.受け取ったクライアントが表示する

こういった流れで行われます。

ここで気を付けなければいけないのは、日付をまたいだかどうかを最終的に判断するのはサーバー側で判定が行われることになります。
たとえば下記のような形でDBサーバーでは最終ログイン日時を記録しています。

画像7

user_id 1で、ログイン通信が走った際にはこの情報を取得してきて、サーバー上の現在時刻と比較します。現在は 8/16 0:12とします。
8/15 10:12が最終ログインなので、日付を跨いでいます。なので、ログインボーナスを付与します。そして、ログインボーナスの有無にかかわらず日時を書き換えします。

画像8

そして、サーバーはログインボーナスで付与したアイテムの情報等をクライアントに返します。

クライアントはサーバーから返ってきた情報の中にログインボーナスの情報が含まれていればログインボーナスの演出をし、なければスキップします。

あとはクライアント側では起動時、およびクライアント側での判断での日付跨ぎが発生したタイミングで通信を発行してもらえれば良いというわけです。もしクライアント側での日付跨ぎ判定で間違っていても、何も行われない通信が発生するだけです。

このような感じでガチャ及びログインボーナスについて簡単ではありますが、書き起こししました。


この記事が気に入ったらサポートをしてみませんか?