随笔-自控概率的大转盘抽奖

        最近项目需要做一个大转盘抽奖功能,抽奖的道具、数量及概率都有策划配置。废话不多说,先上配置表:

[
{"id":0,"type":1,"num":5,"proportion":20},
{"id":1,"type":0,"num":1500,"proportion":7},
{"id":2,"type":1,"num":20,"proportion":8},
{"id":3,"type":0,"num":500,"proportion":15},
{"id":4,"type":1,"num":5,"proportion":20},
{"id":5,"type":0,"num":1500,"proportion":7},
{"id":6,"type":1,"num":20,"proportion":8},
{"id":7,"type":0,"num":500,"proportion":15}
]

        对应的C#的实体类如下:

public class PrizeWhellData
{
    /// <summary>
    /// id
    /// </summary>
    public int id;

    /// <summary>
    /// 类型(0:金币;1:钻石;2:装饰币;3:各种道具预留)
    /// </summary>
    public int type;

    /// <summary>
    /// 数值
    /// </summary>
    public int num;

    /// <summary>
    /// 占比
    /// </summary>
    public float proportion;
}

        接下来就是转盘的功能了:

  • 首先是初始化阶段,配表Json解析这里就不写了。已经存在prizeWhellDataDic这个字典里了。
    public Transform RollPanel;//旋转的转盘
    public Button startBtn;//开始按钮
    private bool isClick;
    int rollID;

    #region 转盘相关
    RollState curState; //当前转盘的状态
    float allTime = 0;//旋转时间  总的时间
    float endAngle;//最终的角度

    //变速段
    float MaxSpeed = 800;//最大速度
    float factor;//速度因子
    float accelerateTime = 1;//加速到最大速度的时间 ---暂定为1
    float speedUpTime = 3;//加速段的总时间
    float tempAngle;//开始减速段时转盘此时的旋转角度
    float k = 2f; //减速阶段的速度系数 --减速快慢由此决定 
    #endregion
    
    //角度,分了8份,所以角度是以下8份
    private string[] angles = new string[8] { "0,45", "45,90", "90,135", 
        "135,180", "180,225", "225,270", "270,315", "315,360" };
    private List<int> rates = new();//几率数组
    public Text[] itemTexts;
    public Image[] itemIcons;

    // 配表数据
    private Dictionary<int, PrizeWhellData> prizeWhellDataDic = new();

    private void Start()
    {
        startBtn.onClick.AddListener(StartBtnEvent);

        for (int i = 0; i < prizeWhellDataDic.Count; i++)
        {
            if (prizeWhellDataDic[i].type == 0)
            {
                //如果是金币,放金币的图片
                itemIcons[i].sprite = GameManager.Instance.GetSpriteAtlas("pw_icon_glodBig");
            }
            else if (prizeWhellDataDic[i].type == 1)
            {
                //如果是钻石,放钻石的图片
                if (prizeWhellDataDic[i].num > 10)
                {
                    itemIcons[i].sprite = GameManager.Instance.GetSpriteAtlas("pw_icon_gemB");
                }
                else
                { 
                    itemIcons[i].sprite = GameManager.Instance.GetSpriteAtlas("pw_icon_gemS");
                }
            }
            itemIcons[i].SetNativeSize();
            itemTexts[i].text = string.Format("x{0}", prizeWhellDataDic[i].num);
            rates.Add((int)prizeWhellDataDic[i].proportion);
        }
        
        //初始化数据
        isClick = true;
        rollID = 0;
        RollPanel.rotation = Quaternion.identity;
        //for (int i = 0; i < 100; i++)
        //{
        //    Debug.LogError("testRandRate:   " + randRate());
        //}
    }
  • 接下来就是旋转的功能逻辑:
    void Update()
    {
        if (curState == RollState.None)
        {
            return;
        }
        allTime += Time.deltaTime;
        //先进入加速阶段
        if (curState == RollState.SpeedUp)
        {
            factor = allTime / accelerateTime;
            factor = factor > 1 ? 1 : factor;
            RollPanel.Rotate(factor * MaxSpeed * Time.deltaTime * new Vector3(0, 0, -1), Space.Self);
        }
        //当旋转时间大于等于了加速段的时间就开始进行减速
        if (allTime >= speedUpTime && curState == RollState.SpeedUp)
        {
            curState = RollState.SpeedDown;
            tempAngle = GetTempAngle();
            //Debug.Log("tempAngle:" + tempAngle);
        }
        if (curState == RollState.SpeedDown)
        {
            //通过差值运算实现旋转到指定角度(球型插值无法实现大于360°的计算)
            tempAngle = Mathf.Lerp(tempAngle, endAngle, Time.deltaTime * k);
            RollPanel.rotation = Quaternion.Euler(0, 0, tempAngle);

            //旋转结束
            if (Mathf.Abs(tempAngle - endAngle) <= 1)
            {
                curState = RollState.None;
                StartCoroutine(End());
            }
        }
    }

    private IEnumerator End()
    { 
        //奖励rollid
        if (prizeWhellDataDic.ContainsKey(rollID))
        {
            int numCount = prizeWhellDataDic[rollID].num;
            if (prizeWhellDataDic[rollID].type == 0)
            {//金币
                UIController.Instance._uiMain._goldRec.GetComponent<Canvas>().overrideSorting = true;

                Vector3 endPos = UIController.Instance._uiMain._currentGoldImg.transform.position;
                TweenUtility.PlayBoomCoinFly(Vector3.zero, endPos, numCount, 1.2f);
                AudioManager.Instance.PlayAudio("box_gold");
            }
            else if (prizeWhellDataDic[rollID].type == 1)
            { //钻石
                UIController.Instance._uiMain._diamondRec.GetComponent<Canvas>().overrideSorting = true;

                Vector3 endPos = UIController.Instance._uiMain._currentDiamondImg.transform.position;
                TweenUtility.PlayBoomCoinFly(Vector3.zero, endPos, numCount, 1.2f);
                AudioManager.Instance.PlayAudio("box_gem");
            }
        }

        yield return new WaitForSeconds(1.5f);

        if (prizeWhellDataDic.ContainsKey(rollID))
        {
            if (prizeWhellDataDic[rollID].type == 0)
            {//金币
                Debug.Log("获取到了金币:" + prizeWhellDataDic[rollID].num);
            }
            else if (prizeWhellDataDic[rollID].type == 1)
            { //钻石
                Debug.Log("获得了钻石:" + prizeWhellDataDic[rollID].num);
            }
        }
        startBtn.gameObject.SetActive(true);
        isClick = true;
    }

    private void StartBtnEvent()
    {
        startBtn.gameObject.SetActive(false);

        if (!isClick) return;
        StartTurnWheel();
    }

    /// <summary>
    /// 开始旋转转盘
    /// </summary>
    public void StartTurnWheel()
    {
        if (curState != RollState.None)
        {
            return;
        }

        isClick = false;

        allTime = 0;
        tempAngle = 0;
        rollID = randRate();
        endAngle = GetEndAngle(rollID);
        //Debug.LogError("rollID: " + rollID + "    endAngle: " + endAngle);
        curState = RollState.SpeedUp;
    }

    //  0      1      2        3        4        5        6        7     
    //(0,45)(45,90)(90,135)(135,180)(180,225)(225,270)(270,315)(315,360)
    //获取旋转的结果,通过设定的概率然后随机得到结果,我们可以自定义概率

    /// <summary>
    /// 得到当前转盘的旋转角度
    /// </summary>
    /// <returns></returns>
    private float GetTempAngle()
    {
        //Debug.Log("RollPanel.eulerAngles.z: " + RollPanel.eulerAngles.z);
        return (360 - RollPanel.eulerAngles.z) % 360;
    }

    /// <summary>
    /// 计算结束时的角度,因为是顺时针旋转所以是负的
    /// </summary>
    /// <param name="rollId"></param>
    /// <returns></returns>
    private float GetEndAngle(int rollId)
    {
        float min = CFunc.ObjToFloat(angles[rollId].Split(",")[0]);
        float max = CFunc.ObjToFloat(angles[rollId].Split(",")[1]);
        return -(360 - Random.Range(min + 5, max - 5));
    }
    
    //rate:几率数组(%),  total:几率总和(100%)
    public int randRate(int total = 100)
    {
        int rand = Random.Range(0, total + 1);
        for (int i = 0; i < rates.Count; i++)
        {
            rand -= rates[i];
            if (rand <= 0)
            {
                return i;
            }
        }
        return 0;
    }

    /// <summary>
    /// 转盘旋转的四种状态
    /// </summary>
    public enum RollState
    {
        None,
        SpeedUp,
        SpeedDown,
        End
    }

 这就是大转盘的基本功能。可以在其中添加一些特效和动画效果。

猜你喜欢

转载自blog.csdn.net/zhangchong5522/article/details/126950489