JavaScript(Nuxt.js)でソシャゲのガチャシミュレータを作ってみた

シェアする:

この記事をおすすめしたい人

  • ガチャシミュを作りたい人
  • 配列からランダムに要素を取り出したい人
  • つまりオレ

今回は、ソシャゲ?ガチャゲ?というのか、スマホのアプリでガチャを回すゲームありますよね。

あれのシミュレータを自作してみようと思います。

開発環境はNuxt.jsですが、いつも通り仕組みや考え方を実例に沿って書いていくので、他の開発環境にも流用しやすいはず。

しかしガチャシミュって需要あるんですかね。

あれ回しても何の意味もないと思うんですけど…。

需要ないかもですけど、仕組みを考え始めたら楽しくなってしまったので、やっていきますよー。

まずは作ろうとしているガチャの調査

インペリアル サガ エクリプスのガチャシミュを作ろうと思います。

さっそく開催中のガチャの提供割合を見てみるとこの↓ような感じ。

それぞれの確率をまとめると次のようになります。

種類確率合計
伝説キャラ0.30000%10.30000%
★5キャラ1.00000%22.00000%
★5キャラ0.02898%691.99962%
★4キャラ0.16438%7311.99974%
★3キャラ1.38837%4359.69991%
★5装備2.00000%24.00000%
★5装備0.01257%1591.99863%
★4装備4.00000%14.00000%
★4装備0.15053%9313.99929%

各項目の合計確率をさらに合計すると99.99719%になります。

合計が100%になっていませんが、これは公式の説明にもある通り、小数点第6位以下を四捨五入?切り捨て?しているからです。

しかしながら100%に届いていないこのままの確率通りにガチャシミュを作った場合、切り捨てられた0.00281%の部分にマッチした時、

え、どうなんの?

実装の仕方にもよりますが、おそらくnullが入るんでしょう。

10連ガチャして9個しか出なかったらクレームもんです。

かと言って、nullを出さないように数値通りの確率で調整した場合、

それって実際のガチャと同じ確率になってんの?

この辺がこだわるポイントかなーと。

対して、レアリティごとの排出率はこの↓ように非常に綺麗な数字で書かれています。

つまりですね、先にレアリティの判定を行って、その後にレアリティ内で均等杯分してるんじゃないのかなーと思うわけです。

以下、そういう認識で、実際の処理を考えていきます。

開発環境がNuxt.jsというかVue.jsというかNode.jsというかJavaScriptなので、JavaScriptの表記になっていますが、別の言語で書いている場合は各言語の仕様に合わせて書き換えてください。

レアリティの抽選処理

乱数で1~100までの値を生成し、それが各レアリティのどの部分にヒットするか、みたいなイメージでやってみます。

JavaScriptの乱数生成をMDNで調べてみると、ちょうど欲しい具体例↓がありました。


Math.floor(Math.random() * 10);

これで整数の0~9が返るそうです。

となると、データをこの↓ような形で用意して、


[
  { rarity: 5, rate: 10 },
  { rarity: 4, rate: 30 },
  { rarity: 3, rate: 60 },
]

乱数が0~9なら★5、10~29なら★4、30~99なら★3のように処理してやればよさそうです。

具体的なコードにするとこんな↓感じ。


//乱数を生成
const value = Math.floor(Math.random() * 100);

//確率処理用の現在値
let current = 0;

//レアリティの配列でループ
for ( let i = 0; i < json.length; i++ ) {
  //現在値に確率を加算
  current += json.rate;
  
  //乱数が現在値未満なら当たり
  if ( value < current ) {
    //当たりの処理
  }
}

実際のガチャには小数点第1位まであるレアリティもあるので、乱数は1000までで生成してその後に10で割ります。

レアリティ内の均等抽選処理

まず、各レアリティで均等に当たるキャラを配列↓で用意します。


[
  'アルベルト',
  'ジャミル',
  'グレイ',
  'ホーク',
  'アイシャ',
  …
]

シンプルに名前のテキストにしていますが、オブジェクトでも大丈夫です。

あとはランダムに配列から1要素取り出せばいいだけなので、先ほどと同様に乱数を利用して、当たりの判定はこの↓ようになります。


//乱数を生成
const value = Math.floor(Math.random() * json.length);

//INDEXが乱数のキャラが当たり
const match = json(value);

ガチャのデータ構造を考える

ここまでの流れから実際のガチャに即してデータ構造を考えると、

  • レアリティごとに確率を設定
  • キャラと装備の区別
  • レアリティごとにキャラや装備を配列で持たせる

[
  {
    rarity: 5,
    rate: 10,
    isEquipment: false,
    aLineup: [
      'アルベルト',
      'ジャミル',
      'グレイ',
      'ホーク',
      'アイシャ',
      …
    ],
  },
  …
]

最終的なガチャの処理

上記ガチャデータを変数「json」に持っているものとして、1回のガチャの抽選処理はこの↓ようになります。


//乱数を生成
const value = Math.floor(Math.random() * 1000) / 10;

//確率処理用の現在値
let current = 0;

//レアリティの配列でループ
for ( let i = 0; i < json.length; i++ ) {
  //現在値に確率を加算
  current += json.rate;
  
  //乱数が現在値未満なら当たり
  if ( value < current ) {
    //配列から取り出す用の乱数を生成
    const index = Math.floor(Math.random() * json[i].aLineup.length);
    
    当たりの確定
    const match = json[i].aLineup[index]
    
    //以下、当たりの処理
  }
}

あとは10連目だけ★5の確率が高いとか、★4保証があるとかのボーナスがあるケースがあるので、それの処理を挟んで、10連分の処理をすればこの↓通り。

やってみるとちょっと楽しいですねコレ。

完成したガチャシミュがコレです。

以上、WordPressからお届けしました!

シェアする: