最近项目需要做一个大转盘抽奖功能,抽奖的道具、数量及概率都有策划配置。废话不多说,先上配置表:
[
{"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());
//}
}
- 接下来就是旋转的功能逻辑:
文章来源地址https://www.toymoban.com/news/detail-604601.html
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
}
这就是大转盘的基本功能。可以在其中添加一些特效和动画效果。文章来源:https://www.toymoban.com/news/detail-604601.html
到了这里,关于随笔-自控概率的大转盘抽奖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!