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

根据权重,获得随机物品

  • 需求
  • 代码
  • 使用方式
    • AddWeightItem(int item,int weight)
    • GetRandomWeightDeleteValueIrrecoverable()
    • GetRandomWeightDeleteValueRecoverable()
    • Recovery()
    • GetRandomWeightValue()
  • 实例使用代码
  • 总结
  • 文章历史

需求

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

代码

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

        /// 
        /// 获取随机值(删除,可恢复)
        /// 
        /// 
        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;
            }
        }

        /// 
        /// 获取随机值(删除,不可恢复)
        /// 
        /// 
        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;
            }
        }

        /// 
        /// 恢复已经使用过的种子
        /// 
        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;
        }
        /// 
        /// 获取权重区域
        /// 
        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 testModdules = new List();

    // 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 randomWeightHelper = new GameWish.Game.RandomWeightHelper();

        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,可恢复或者不恢复功能。

你可能感兴趣的:(游戏开发,unity,c#)