游戏开发模块:根据权重,获得随机物品

需求

奖励物品的时候,需要根据策划配表的权重,来随机获得物品。

代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/**
 * 
 * 权重随机
 * 
 * 
 */
namespace GameWish.Game
{

    public class RandomRange
    {
        public int Start { set; get; }
        public int End { set; get; }
        public RandomRange(int start, int end) { Start = start; End = end; }
    }
    public class RandomWeightHelper<T>
    {
        private Dictionary<T, int> m_WeightItemDic = new Dictionary<T, int>();
        private Dictionary<T, RandomRange> m_WeightItemSectionDic = new Dictionary<T, RandomRange>();

        private Dictionary<T,int> m_Cache = new Dictionary<T, int>();
        private int m_AllWeight = 0;

        public RandomWeightHelper()
        {

        }

        #region Public
        /// <summary>
        /// 添加权重子项
        /// </summary>
        /// <param name="id"></param>
        /// <param name="weight"></param>
        public void AddWeightItem(T id, int weight = 1)
        {
            if (!m_WeightItemDic.ContainsKey(id))
            {
                m_WeightItemDic.Add(id, weight);
            }
        }
        /// <summary>
        /// 获取随机key,不删除
        /// </summary>
        /// <returns></returns>
        public T GetRandomWeightValue()
        {
            if (m_WeightItemDic.Count > 0)
            {
                GetWeightItemSectionDic();
                int randomNumber = Random.Range(0, GetAllWeight());
                return GetRandomKey(randomNumber);
            }
            else
            {
                Debug.Log("随机池中无种子");
                return default;
            }
        }

        /// <summary>
        /// 获取随机值(删除,可恢复)
        /// </summary>
        /// <returns></returns>
        public T GetRandomWeightDeleteValueRecoverable()
        {
            if (m_WeightItemDic.Count > 0)
            {
                GetWeightItemSectionDic();
                int randomNumber = Random.Range(0, GetAllWeight());
                T cont = GetRandomKey(randomNumber);

                if (m_WeightItemDic.ContainsKey(cont))
                {
                    m_WeightItemDic.Remove(cont);
                    m_Cache.Add(cont, m_WeightItemDic[cont]);
                }
                else
                    Debug.LogError("未找到值,cont = " + cont);
                return cont;
            }
            else
            {
                Debug.Log("随机池中无种子");
                return default;
            }
        }

        /// <summary>
        /// 获取随机值(删除,不可恢复)
        /// </summary>
        /// <returns></returns>
        public T GetRandomWeightDeleteValueIrrecoverable()
        {
            if (m_WeightItemDic.Count > 0)
            {
                GetWeightItemSectionDic();
                int randomNumber = Random.Range(0, GetAllWeight());
                T cont = GetRandomKey(randomNumber);

                if (m_WeightItemDic.ContainsKey(cont))
                    m_WeightItemDic.Remove(cont);
                else
                    Debug.LogError("未找到值,cont = " + cont);
                return cont;
            }
            else
            {
                Debug.Log("随机池中无种子");
                return default;
            }
        }

        /// <summary>
        /// 恢复已经使用过的种子
        /// </summary>
        public void Recovery()
        {
            foreach (var item in m_Cache)
            {
                m_WeightItemDic.Add(item.Key, item.Value);
            }
        }

        public void ClearAll()
        {
            m_WeightItemDic.Clear();
            m_WeightItemSectionDic.Clear();
            m_Cache.Clear();
        }
        #endregion

        #region Private
        private int GetAllWeight()
        {
            int allWeight = 0;
            if (m_WeightItemDic.Count <= 0)
            {
                return 1;
            }

            foreach (var item in m_WeightItemDic)
            {
                allWeight += item.Value;
            }
            return allWeight;
        }

        private T GetRandomKey(int randomNumber)
        {
            T key = default;
            if (m_WeightItemSectionDic.Count <= 0)
            {
                Debug.Log("随机区域未空");
                return key;
            }
            foreach (var item in m_WeightItemSectionDic)
            {
                if (item.Value.Start <= randomNumber && item.Value.End > randomNumber)
                {
                    key = item.Key;
                }
            }
            return key;
        }
        /// <summary>
        /// 获取权重区域
        /// </summary>
        private void GetWeightItemSectionDic()
        {
            m_WeightItemSectionDic.Clear();
            List<T> keys = new List<T>();
            keys.AddRange(m_WeightItemDic.Keys);
            List<int> values = new List<int>();
            values.AddRange(m_WeightItemDic.Values);
            for (int i = 0; i < keys.Count; i++)
            {
                int preWight = 0;
                int curWight = 0;

                for (int j = 0; j < values.Count; j++)
                {
                    curWight += values[j];
                    preWight += values[j];
                    if (i <= j)
                    {
                        preWight -= values[j];
                        break;
                    }
                }
                if (!m_WeightItemSectionDic.ContainsKey(keys[i]))
                    m_WeightItemSectionDic.Add(keys[i], new RandomRange(preWight, curWight));

            }
        }
        #endregion
    }
}


使用方式

AddWeightItem(int item,int weight)

第一个参数为随机的对象,将来做返回使用,第二个是权重信息

GetRandomWeightDeleteValueIrrecoverable()

随机获得一个上一个函数添加进去的类对象(获取后删除,不可以恢复)

GetRandomWeightDeleteValueRecoverable()

随机获得一个上一个函数添加进去的类对象(获取后删除,可以恢复)

Recovery()

恢复已经使用过的种子

GetRandomWeightValue()

随机获得一个上一个函数添加进去的类对象(获取后不删除)

实例使用代码

public class Text : MonoBehaviour
{
    public class TestModdule
    {
        public int value;
        public int weight;
        public TestModdule(int value, int weight)
        {
            this.value = value;
            this.weight = weight;
        }
    }

    private List<TestModdule> testModdules = new List<TestModdule>();

    // Start is called before the first frame update
    void Start()
    {
        testModdules.Add(new TestModdule (0,60));
        testModdules.Add(new TestModdule (1,30));
        testModdules.Add(new TestModdule (2,10));

        RandomWeightHelper<TestModdule> randomWeightHelper = new GameWish.Game.RandomWeightHelper<TestModdule>();

        foreach (var item in testModdules)
        {
            randomWeightHelper.AddWeightItem(item, item.weight);
        }
        for (int i = 0; i < 1000; i++)
        {
            TestModdule test1Moddule = randomWeightHelper.GetRandomWeightValue();
            Debug.LogError(test1Moddule.value);
            //Debug.LogError("第"+i+"次权重随机:" + test1Moddule.value);
            //TestModdule test2Moddule = randomWeightHelper.GetRandomWeightValue();
            //Debug.LogError(test2Moddule.value);
            Debug.LogError("第" + i + "次权重随机:" + test2Moddule.value);
            //TestModdule test3Moddule = randomWeightHelper.GetRandomWeightValue();
            //Debug.LogError(test3Moddule.value);
            Debug.LogError("第" + i + "次权重随机:" + test3Moddule.value);
        }


    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

总结

百度搜索不到相应的直接能用的代码,故自己写一个公使用,有更好的请私信联系。

文章历史

  • 2021/4/26 第一次修正,增加获取随机值后删除Api。
  • 2021/7/14 第二次修正,增加获取随机值后删除Api,可恢复或者不恢复功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是小狼君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值