GS2-Lottery

抽選処理機能

ガチャを実装するための仕組みです。 GS2-Lottery では、通常ガチャとボックスガチャに対応しています。

graph TD
  Trigger["抽選トリガー<br/>(GS2-Showcase の購入報酬 / クエストクリア報酬 など)"] --> LotteryModel["LotteryModel<br/>(抽選モデル)"]
  LotteryModel -- "mode = normal" --> Normal["通常モード抽選"]
  LotteryModel -- "mode = box" --> Box["ボックスモード抽選"]
  Normal --> PrizeTable["景品テーブル<br/>(PrizeTable)"]
  Box --> BoxData["プレイヤー専有ボックス"]
  PrizeTable --> Prize["Prize<br/>(acquireActions)"]
  BoxData --> Prize
  Prize --> Acquire["GS2-Distributor<br/>報酬配布"]

通常ガチャ

通常ガチャは指定された確率で純粋な抽選を行います。

景品テーブル

景品テーブルとは、ガチャを実行した時に出てくる景品の排出確率を定義したものです。 マスターデータとして定義することになります。

重み

景品テーブルでの確率の設定は、景品ごとの重みを設定します。 具体的には以下のようなテーブルを作成することになります。

重み
景品A 1
景品B 2
景品C 4

これを百分率による確率として解釈すると以下のように解釈できます。

重み 確率
景品A 1 14.285%
景品B 2 28.571%
景品C 4 57.143%

百分率ベースで確率を設定する必要がある場合、全てを足して100%になるよう考える必要がありますが 重みベースで確率を設定する場合は、そのような負担をする必要がなくなります。

景品テーブルの入れ子

景品テーブルは、最大5層まで入れ子にすることができます。

具体的な使用方法としては

  • SSRキャラクターの排出確率を3%
  • SRキャラクターの排出確率を7%
  • Rキャラクターの排出確率を90%

という基本指針に基づいて排出キャラクターを設定したい時に便利です。 この場合は2層で、4個の景品テーブルを定義することになります。

レアリティ抽選用景品テーブル

重み 景品の種類 抽選テーブル名
SSR 3 景品テーブルの入れ子 SSRキャラクター抽選用景品テーブル
SR 7 景品テーブルの入れ子 SRキャラクター抽選用景品テーブル
R 90 景品テーブルの入れ子 Rキャラクター抽選用景品テーブル

SSRキャラクター抽選用景品テーブル

重み 景品の種類 抽選テーブル名
SSR-0001 1 入手処理 SSR-0001 を GS2-Dictionary に記録
SSR-0002 1 入手処理 SSR-0002 を GS2-Dictionary に記録
SSR-0003 1 入手処理 SSR-0003 を GS2-Dictionary に記録

SRキャラクター抽選用景品テーブル

重み 景品の種類 抽選テーブル名
SR-0001 1 入手処理 SR-0001 を GS2-Dictionary に記録
SR-0002 1 入手処理 SR-0002 を GS2-Dictionary に記録
SR-0003 1 入手処理 SR-0003 を GS2-Dictionary に記録

Rキャラクター抽選用景品テーブル

重み 景品の種類 抽選テーブル名
R-0001 1 入手処理 R-0001 を GS2-Dictionary に記録
R-0002 1 入手処理 R-0002 を GS2-Dictionary に記録
R-0003 1 入手処理 R-0003 を GS2-Dictionary に記録

ボックスガチャ

ボックスガチャはマスターデータで定義された景品を指定された数量ずつボックスに投入し 抽選処理を行うときにはボックスから景品を取り出していくことで景品の内容を決定します。

つまり、100個の景品のうち1個「アタリ」を入れているボックスを用意した場合、100回以内にかならず「アタリ」景品が抽選されます。

ボックスへの景品の投入

ボックス内部の景品の設定にも景品テーブルを使用します。 通常抽選モードでは排出の重みを設定しましたが、重みのパラメーターにはボックス内に景品を投入する数量を設定します。

重み
景品A 1
景品B 2
景品C 4

この場合、ボックスには最初7個の景品が入っており「景品Aが1個」「景品Bが2個」「景品Cが4個」入っている状態になります。

ボックスのリセット

ボックスは「ボックスのリセット」アクションにより中身を初期状態に戻すことができます。 プレイヤーごとに独立したボックスを持つため、コンプリート報酬の付与後にボックスを引き直したい、月替わりでボックスを更新したい、といった用途で利用できます。

抽選モデル

抽選モデルでは、景品テーブルのうち抽選APIで使用できる景品テーブルを指定します。 マスターデータとして定義することになります。

上記例で言えば、抽選APIを呼び出した時に いきなり SSRキャラクター抽選用景品テーブル を使って抽選処理が行えてしまうと不安です。

抽選モデルで以下のようなマスターデータを定義しておき

抽選モデル名 景品テーブル名
ガチャ レアリティ抽選用景品テーブル

抽選処理を呼び出す際には 抽選モデル名に「ガチャ」を指定して抽選することになります。

抽選モード(mode)と抽選方法(method)

抽選モデルでは mode で抽選の方式を、method で景品テーブルの参照方法を指定します。

mode 説明
normal 通常モード(指定された確率で毎回独立に抽選を行う)
box ボックスモード(プレイヤー固有のボックスから景品を取り出す)
method 説明
prize_table 静的に指定された景品テーブルを使用する
script GS2-Script を使って動的に景品テーブルを選択する

スクリプトによる景品テーブル選択

methodscript に設定し、choicePrizeTableScriptId を指定すると、抽選実行時に GS2-Script を呼び出して動的に使用する景品テーブルを選択できます。 プレイヤーごとの確率変更(天井システム)や、開催中イベントに応じた景品テーブル切り替えを実現できます。

スクリプトトリガー

ネームスペースに lotteryTriggerScriptId を設定すると、抽選処理の前に GS2-Script を同期実行できます。スクリプトでは抽選の許可/不許可を判定したり、抽選結果を上書きすることが可能です。

設定できる主なイベントトリガーとスクリプト設定名は以下の通りです。

  • lotteryTriggerScriptId: 抽選処理の前に同期実行

抽選結果の検証や、特定条件下での結果の差し替えといったカスタム処理を実装できます。

トランザクションアクション

GS2-Lottery では以下のトランザクションアクションを提供しています。

  • 入手アクション: 抽選の実行、ボックスのリセット

「抽選の実行」を入手アクションとして利用することで、ショップでの商品購入時やクエストクリア時の報酬として、直接ガチャ(抽選)を実行するといった処理が可能になります。また、「ボックスのリセット」を入手アクションに含めることで、特定のアイテムを入手したタイミングや、イベントの節目に、ボックスガチャの中身を自動的にリセットして最初から引き直せる状態にするといった制御をトランザクション内で安全に行えます。

マスターデータ運用

マスターデータを登録することでマイクロサービスで利用可能なデータや振る舞いを設定できます。

マスターデータの種類には以下があります。

  • LotteryModel: 抽選モデル。抽選方式と利用する景品テーブルを定義します。
  • PrizeTable: 景品テーブル。景品の重みと入手アクション、または入れ子の景品テーブルを定義します。
  • Prize: 景品の単位。acquireActions で得られる報酬を指定し、drawnLimitlimitFailOverPrizeId で排出制限とフェイルオーバー先を設定できます。

マスターデータの登録はマネージメントコンソールから登録する他、GitHubからデータを反映したり、GS2-Deployを使ってCIから登録するようなワークフローを組むことが可能です。

以下はマスターデータの JSON 例です。

{
  "version": "2019-02-21",
  "lotteryModels": [
    {
      "name": "lottery-0001",
      "metadata": "通常ガチャ",
      "mode": "normal",
      "method": "prize_table",
      "prizeTableName": "rarity"
    }
  ],
  "prizeTables": [
    {
      "name": "rarity",
      "metadata": "レアリティ抽選",
      "prizes": [
        {
          "prizeId": "ssr",
          "type": "prize_table",
          "prizeTableName": "ssr-prizes",
          "weight": 3
        },
        {
          "prizeId": "sr",
          "type": "prize_table",
          "prizeTableName": "sr-prizes",
          "weight": 7
        },
        {
          "prizeId": "r",
          "type": "prize_table",
          "prizeTableName": "r-prizes",
          "weight": 90
        }
      ]
    }
  ]
}

実装例

抽選の実行

抽選の実行はゲームエンジン用の SDK では処理できません。

GS2-Showcase の商品購入の報酬として抽選を実行するといった方法で実装してください。GS2-Showcase の acquireActions に GS2-Lottery の DrawByUserId を含めることで、購入処理のトランザクションとして抽選を実行できます。

排出確率の取得

景品の表示用に、現在のプレイヤーに対する排出確率を取得できます。 排出数量の制限(後述)が掛かっている場合、その影響を反映した確率が返却されます。

    var items = await gs2.Lottery.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).ProbabilitiesAsync(
        lotteryName: "lottery-0001"
    ).ToListAsync();
    const auto It = Gs2->Lottery->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Probabilities(
        "lottery-0001" // lotteryName
    );
    TArray<Gs2::UE5::Lottery::Model::FEzProbabilityPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

ボックスの中身を取得

    var item = await gs2.Lottery.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).BoxItems(
        prizeTableName: "prizeTable-0001"
    ).ModelAsync();
    const auto Domain = Gs2->Lottery->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->BoxItems(
        "prizeTable-0001" // prizeTableName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    const auto Result = Future->GetTask().Result();

ボックスのリセット

    var result = await gs2.Lottery.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).BoxItems(
        prizeTableName: "prizeTable-0001"
    ).ResetBoxAsync(
    );
    const auto Future = Gs2->Lottery->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->BoxItems(
        "prizeTable-0001" // prizeTableName
    )->ResetBox(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

抽選モデル一覧を取得

UI でガチャ一覧を表示する用途で、ネームスペース内に定義された抽選モデルを取得できます。

    var items = await gs2.Lottery.Namespace(
        namespaceName: "namespace-0001"
    ).LotteryModelsAsync(
    ).ToListAsync();
    const auto It = Gs2->Lottery->Namespace(
        "namespace-0001" // namespaceName
    )->LotteryModels();
    TArray<Gs2::UE5::Lottery::Model::FEzLotteryModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

その他の機能

景品の排出数量の制限

通常モードで動作させている時に、景品ごとに排出数量の上限を設定できます。 この機能を利用すると Probabilities 関数が応答する確率と実際の確率の齟齬が生じます。 Probabilities を使用して排出確率の表示を行う際には、この機能は利用するべきではありません。

用途として想定されているのは物理景品を配布するための抽選処理です。 確率1%で排出されるギフト券があったとして、ギフト券は100枚しか準備がないケースでこの機能が役立ちます。 ギフト券の排出数量の上限を100に設定し、フェイルオーバー景品にはずれや、異なるあたり景品を設定します。

このように設定することで、すでにギフト券を100枚排出済みの状態で、ギフト券が当選した場合 ギフト券の代わりにフェイルオーバー景品に設定した景品が排出されます。 フェイルオーバー景品に数量制限が設定されている場合は、同様の制限が適用されます。

詳細なリファレンス