3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unityでゲームのガチャシステム

Last updated at Posted at 2022-09-07

はじめに

Unityでゲームのガチャシステムを作るのに今回は重み付きの抽選方法を使っていきます。
重み付きの抽選方法を選んだ理由は、確率を合計100%にしなくてもいいので計算が楽でピックアップ対応しやすいと思ったからです。
ガチャの排出率、内容は実際のゲーム( テイルズオブザレイズ )のガチャの排出率、内容を参考にしています。

環境

 Windows10
 Unity 2019.4.11f1

作業

抽選を行って、コンソールにアイテム名を表示するスクリプトを作成していきます。
サイトを参考にしながら作業を進めます。

まずは、レアリティ別のガチャを作ります。

状況設定

   レア度    確率(10連 1/10回)   確率(1連、10連 9/10回) 
星6魔境 5% 5%
星5鏡技 6% 6%
星4装備 89% 15%
星3装備 0% 74%

レアリティ別の排出率をスクリプトで読み込めるようにテキストにまとめます。

RarityData.txt
74,15,6,5
0,89,6,5

RarityDataは、
上の行が確率(1連、10連 9/10回)で下の行が確率(10連 1/10回)
左から ☆3 , ☆4 , ☆5 , ☆6 の排出率(%)になっています。

Lottery.cs
    [SerializeField]
    TextAsset RarityData = default;

    float[,] RarityInfo;
    int rollNum = 0;
    int lotteryType;//0=1連,1=10連(1/10回)

    string[] raw;
    string[] column;

    void Start()
    {
        //textの読み込み
        raw = RarityData.text.Split('\n');
        column = raw[0].Split(',');
        RarityInfo = new float[column.Length,raw.Length];
        for (int i = 0; i < raw.Length; i++)
        {
            column = raw[i].Split(',');
            for (int j = 0; j < column.Length; j++)
                RarityInfo[j, i] = float.Parse(column[j]);
        }
    }

    void Update()
    {
        for(int i=0;i<rollNum;i++)
        {
            if (i == 9)//最後の1回
                lotteryType = 1;
            else
                lotteryType = 0;
            GetDropItem();
        }
        rollNum = 0;
    }

    void GetDropItem()
    {
        //レア度の抽選
        int itemRarity = ChooseRarity() + 3;

        Debug.Log(itemRarity);
    }

    int ChooseRarity()
    {
        //確率の合計値を格納
        float total = 0;

        //確率を合計する
        for (int i = 0; i < RarityInfo.GetLength(0); i++)
                total += RarityInfo[i,lotteryType];

        //Random.valueでは0から1までのfloat値を返すので
        //そこにドロップ率の合計を掛ける
        float randomPoint = Random.value * total;

        //randomPointの位置に該当するキーを返す
        for(int i = 0;i< RarityInfo.GetLength(0); i++)
        {
            if (randomPoint < RarityInfo[i, lotteryType])
            {
                return i;
            }
            else
            {
                randomPoint -= RarityInfo[i, lotteryType];
            }
        }
        return 0;
    }

    //ボタン用
    public void lotteryTypeOne()
    {
        rollNum = 1;
    }
    public void lotteryTypeTen()
    {
        rollNum = 10;
    }

InspectorのRarityDataの欄にRarityData.txtをドラッグアンドドロップします。
ボタンを2つ作り、それぞれに lotteryTypeOne と lotteryTypeTen を設定します。

結果

確率(1連、10連 9/10回)を10000回
Debug1.png
確率(10連 1/10回)を10000回
Debug2.png
概ね設定した確率通りになりました。
確率(1連、10連 9/10回)と確率(10連 1/10回)をあわせて10000回
Debug3.png
確率(1連、10連 9/10回)より 3 が減って 4 , 5 , 6 が増えました。

これでレアリティ別のガチャが出来ました。
次に、レアリティに応じたアイテムの中からさらに抽選していきます。

状況設定

 レア度   名前   確率   レア度   名前   確率 
星6魔境 空を羽ばたいて 1.000 星4装備 クリスタルミラー 2.500
星6魔境 不器用に舞う剣 1.000 星4装備 龍眼鏡 2.500
星6魔境 我が道を行く狙撃者 1.000 星4装備 ミスティシェイプ 2.500
星6魔境 浜辺のエンジェル 0.500 星4装備 ツヴァイチャクラム 2.500
星6魔境 EX-clipse ボーカル 0.500 星4装備 アヌビス 2.500
星6魔境 君と歩く浜辺 0.500 星4装備 ミルキーウェイ 2.500
星6魔境 絵馬で願掛け 0.500 星3装備 シルバーミラー 4.933
星5鏡技 天然剣士 コレット 1.250 星3装備 レフリフレクト 4.933
星5鏡技 狙い鋭いスナイパー リタ 1.250 星3装備 光鏡 4.933
星5鏡技 哀傷の鏡士 ミリーナ 0.500 星3装備 鬼灯 4.933
星5鏡技 「想像」の使い手 ミリーナ 0.500 星3装備 ロイヤルミラー 4.933
星5鏡技 新たなる歩み ミリーナ 0.500 星3装備 シェルフレーム 4.933
星5鏡技 天使化する身体 コレット 0.500 星3装備 トーロイド 4.933
星5鏡技 爽涼スプラッシュ コレット 0.500 星3装備 スティングソーサー 4.933
星5鏡技 魔導器とともに リタ 0.500 星3装備 サイケデリカ 4.933
星5鏡技 白花の髪飾り リタ 0.500 星3装備 エヴァーブルー 4.933
星3装備 パーフェクトグリーン 4.933
星3装備 カクゴノキロク 4.933
星3装備 マフラー 4.933

アイテム別の排出率をテキストにまとめます。

ItemData.txt
6,空を羽ばたいて,1.000
6,不器用に舞う剣,1.000
6,我が道を行く狙撃者,1.000
6,浜辺のエンジェル,0.500
6,EX-clipse ボーカル,0.500
6,君と歩く浜辺,0.500
6,絵馬で願掛け,0.500
5,天然剣士 コレット,1.250
5,狙い鋭いスナイパー リタ,1.250
5,哀傷の鏡士 ミリーナ,0.500
5,「想像」の使い手 ミリーナ,0.500
5,新たなる歩み ミリーナ,0.500
5,天使化する身体 コレット,0.500
5,爽涼スプラッシュ コレット,0.500
5,魔導器とともに リタ,0.500
5,白花の髪飾り リタ,0.500
4,クリスタルミラー,2.500
4,龍眼鏡,2.500
4,ミスティシェイプ,2.500
4,ツヴァイチャクラム,2.500
4,アヌビス,2.500
4,ミルキーウェイ,2.500
3,シルバーミラー,4.933
3,レフリフレクト,4.933
3,光鏡,4.933
3,鬼灯,4.933
3,ロイヤルミラー,4.933
3,シェルフレーム,4.933
3,トーロイド,4.933
3,スティングソーサー,4.933
3,サイケデリカ,4.933
3,エヴァーブルー,4.933
3,パーフェクトグリーン,4.933
3,カクゴノキロク,4.933
3,マフラー,4.933

ItemDataは、
左から レア度 , 名前 , 排出率(%) になっています。
排出率をほかの同じレアリティのアイテムより高くするとピックアップになります。

以下のようにスクリプトに変更を加えます。

Lottery.cs
    [SerializeField]
    TextAsset RarityData = default;
    [SerializeField]
    TextAsset itemDeta = default;

    float[,] RarityInfo;
    string[,] itemInfo;
    int rollNum = 0;
    int lotteryType;//0=1連,1=10連(1/10回)

    string[] raw;
    string[] column;

    enum Item
    {
        Rarity,
        Name,
        Rate,
    }

    void Start()
    {
        //textの読み込み
        raw = RarityData.text.Split('\n');
        column = raw[0].Split(',');
        RarityInfo = new float[column.Length, raw.Length];
        for (int i = 0; i < raw.Length; i++)
        {
            column = raw[i].Split(',');
            for (int j = 0; j < column.Length; j++)
                RarityInfo[j, i] = float.Parse(column[j]);
        }
        raw = itemDeta.text.Split(char.Parse("\n"));
        column = raw[0].Split(char.Parse(","));
        itemInfo = new string[column.Length, raw.Length];
        for (int i = 0; i < raw.Length; i++)
        {
            column = raw[i].Split(char.Parse(","));
            for (int j = 0; j < column.Length; j++)
                itemInfo[j, i] = column[j];
        }
    }

    void Update()
    {
        for (int i = 0; i < rollNum; i++)
        {
            if (i % 10 == 9)//最後の1回
                lotteryType = 1;
            else
                lotteryType = 0;

            GetDropItem();
        }
        rollNum = 0;
    }

    void GetDropItem()
    {
        //レア度の抽選
        int itemRarity = ChooseRarity() + 3;

        //レア度に応じたアイテムの抽選
        int itemId = ChooseItem(itemRarity);

        Debug.Log(itemInfo[(int)Item.Name, itemId]);
    }

    int ChooseRarity()
    {
        //確率の合計値を格納
        float total = 0;

        //確率を合計する
        for (int i = 0; i < RarityInfo.GetLength(0); i++)
            total += RarityInfo[i, lotteryType];

        //Random.valueでは0から1までのfloat値を返すので
        //そこにドロップ率の合計を掛ける
        float randomPoint = Random.value * total;

        //randomPointの位置に該当するキーを返す
        for (int i = 0; i < RarityInfo.GetLength(0); i++)
        {
            if (randomPoint < RarityInfo[i, lotteryType])
            {
                return i;
            }
            else
            {
                randomPoint -= RarityInfo[i, lotteryType];
            }
        }
        return 0;
    }
    int ChooseItem(int rarity)
    {
        float total = 0;

        for (int i = 0; i < itemInfo.GetLength(1); i++)
            if (int.Parse(itemInfo[(int)Item.Rarity, i]).Equals(rarity))
                total += float.Parse(itemInfo[(int)Item.Rate, i]);

        float randomPoint = Random.value * total;

        for (int i = 0; i < itemInfo.GetLength(1); i++)
        {
            if (int.Parse(itemInfo[(int)Item.Rarity, i]).Equals(rarity))
            {
                if (randomPoint < float.Parse(itemInfo[(int)Item.Rate, i]))
                {
                    return i;
                }
                else
                {
                    randomPoint -= float.Parse(itemInfo[(int)Item.Rate, i]);
                }
            }
        }
        return 0;
    }

    //ボタン用
    public void lotteryTypeOne()
    {
        rollNum = 1;
    }
    public void lotteryTypeTen()
    {
        rollNum = 10;
    }

InspectorのItemDetaの欄にItemData.txtをドラッグアンドドロップします。

実行結果

10連を4回まわしてみました。
Debug4.pngDebug5.png
Debug6.pngDebug7.png

☆6=1,☆5=2,☆4=9,☆3=28 という結果になりました。
☆6が出ました。やったー

まとめ

これでピックアップにも対応したゲームのガチャシステムができました。
参考にしたゲームと似たような結果になったと思います。

参考

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?