unity實(shí)現(xiàn)簡(jiǎn)單抽獎(jiǎng)系統(tǒng)
這段時(shí)間工作比較空閑,想做個(gè)抽獎(jiǎng)系統(tǒng),發(fā)現(xiàn)網(wǎng)上的抽獎(jiǎng)系統(tǒng)看不懂,然后自己做了一個(gè)可以隨意定義獎(jiǎng)品概率,不管什么時(shí)候停下來(lái)指針最終都會(huì)轉(zhuǎn)到指定的獎(jiǎng)品哪。
廢話不多說(shuō),動(dòng)手一步一步來(lái)。
這個(gè)抽獎(jiǎng)系統(tǒng)就使用了兩張圖片,一個(gè)指針,一個(gè)圓形的圖片。

然后做一個(gè)預(yù)制體,圖片就是圓形圖片,image type選擇filled,fill amount控制這個(gè)圖片的面積大小,同時(shí)也是該圖片的概率,Text組件是該獎(jiǎng)品的名稱。

再接下來(lái)就做一下界面布局的工作

Bg就是那個(gè)灰色的圖片,Rotate是個(gè)空物體,用來(lái)掛在腳本的(DialRotate.cs和Slot.cs),cloneParent也是個(gè)空物體,作為預(yù)制體的父物體,要注意的是cloneParent中心那個(gè)藍(lán)色的圓圈要和Rotate的藍(lán)色的圈的位置一致,界面布局工作完成。
接下來(lái)到代碼了,Slot.cs腳本,一開(kāi)始會(huì)實(shí)例化獎(jiǎng)品,K鍵和L鍵可以隨意修改獎(jiǎng)品名稱,概率(這里概率做了限制,需要使用的自己修改一下代碼即可),空格鍵會(huì)隨機(jī)拋出物品,并且開(kāi)始旋轉(zhuǎn),鼠標(biāo)右鍵是停止轉(zhuǎn)動(dòng)(想什么時(shí)候停下來(lái)都行,最后都會(huì)得到所拋出的物體)DialRotate.cs腳本用于處理旋轉(zhuǎn)的。這兩個(gè)腳本涉及到一些數(shù)學(xué)計(jì)算,慢慢理解即可。


以下是這個(gè)工程的腳本,需要的話直接復(fù)制黏貼即可使用
Slot.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Slot : MonoBehaviour {
private DialRotate dialRotate;
/// <summary>
/// 獎(jiǎng)品數(shù)據(jù)
/// </summary>
private class GrifData
{
/// <summary>
/// 獎(jiǎng)品的名稱
/// </summary>
public string mText;
/// <summary>
/// 圖片的Amount值
/// </summary>
public float point;
/// <summary>
/// 獎(jiǎng)品停留在指針時(shí)父物體要旋轉(zhuǎn)的角度
/// </summary>
public float angle;
/// <summary>
/// 該獎(jiǎng)品對(duì)應(yīng)UI面板上的名稱
/// </summary>
public string mtran;
/// <summary>
/// 該獎(jiǎng)品的ID
/// </summary>
public int gID;
}
/// <summary>
/// 獎(jiǎng)品的描述信息
/// </summary>
private class GrifInfo
{
public Text mText;
public string msg;
}
private List<GrifInfo> mListSD = new List<GrifInfo>();
/// <summary>
/// 獎(jiǎng)品的id和概率對(duì)應(yīng)
/// </summary>
private Dictionary<int, float> mPoints = new Dictionary<int, float>();
/// <summary>
/// 用于儲(chǔ)存獎(jiǎng)品信息(順序排列)(獎(jiǎng)品的id,名稱,所占的百分比)
/// </summary>
private List<GrifData> grigtData = new List<GrifData>();
/// <summary>
/// 這個(gè)也是用于儲(chǔ)存獎(jiǎng)品信息,不過(guò)是亂序排列(獎(jiǎng)品的id,名稱,所占的百分比)
/// </summary>
private List<GrifData> randomData = new List<GrifData>();
/// <summary>
/// 20種獎(jiǎng)品的Transform,(最多20個(gè)不用的獎(jiǎng)勵(lì))
/// </summary>
private List<Transform> mTransLs = new List<Transform>();
private List<Color> mColors = new List<Color>();
private Transform cloneParent;
private GameObject clonePrefab;
/// <summary>
/// 抽獎(jiǎng)停止時(shí)父物體轉(zhuǎn)動(dòng)的角度
/// </summary>
public float tarAngle;
/// <summary>
/// 該獎(jiǎng)品對(duì)應(yīng)UI面板上的名稱
/// </summary>
public string tarName;
public int giftID;
/// <summary>
/// 用于檢驗(yàn)概率有沒(méi)有為100%
/// </summary>
private List<float> checkProbability = new List<float>();
private void Start()
{
cloneParent = transform.Find("cloneParent");
clonePrefab = Resources.Load<GameObject>("Clone");
dialRotate = GetComponent<DialRotate>();
Init();
}
void Update()
{
#region 測(cè)試修改獎(jiǎng)品,概率
if (Input.GetKeyDown(KeyCode.K))
{
ClearData();
if (checkProbability.Count > 0)
{
checkProbability.Clear();
}
if (mPoints.Count > 0)
{
mPoints.Clear();
}
AddData("111", 0.3f,1);
AddData("222", 0.1f,2);
AddData("333", 0.2f,4);
AddData("444", 0.05f,5);
AddData("555", 0.15f,6);
AddData("666", 0.2f,7);
SetPriceRange();
}
if (Input.GetKeyDown(KeyCode.J))
{
ClearData();
if (checkProbability.Count > 0)
{
checkProbability.Clear();
}
if (mPoints.Count > 0)
{
mPoints.Clear();
}
AddData("薯?xiàng)l", 0.3f, 1);
AddData("漢堡", 0.1f, 2);
AddData("炸雞", 0.2f, 4);
AddData("啤酒", 0.05f, 5);
AddData("可樂(lè)", 0.15f, 6);
AddData("烤肉", 0.2f, 7);
SetPriceRange();
}
#endregion
if (Input.GetKeyDown(KeyCode.Space))
{
StartRotate();
}
}
private void Init()
{
for (int i = 0; i < 20; i++)
{
GameObject go = Instantiate(clonePrefab) as GameObject;
go.transform.SetParent(cloneParent);
go.transform.localScale = Vector3.one;
go.transform.localPosition = Vector3.zero;
go.name = "" + i;
mTransLs.Add(go.transform);
}
foreach (Transform tr in mTransLs)
{
tr.GetComponent<Image>().color = GetColors();
tr.gameObject.SetActive(false);
}
AddData("薯?xiàng)l", 0.3f, 1);
AddData("漢堡", 0.1f, 2);
AddData("炸雞", 0.2f, 4);
AddData("啤酒", 0.05f, 5);
AddData("可樂(lè)", 0.15f, 6);
AddData("烤肉", 0.2f, 7);
SetPriceRange();
}
/// <summary>
/// 獲得隨機(jī)顏色
/// </summary>
/// <returns></returns>
private Color GetColors()
{
return new Color(Random.Range(0, 1.0f), Random.Range(0, 1.0f), Random.Range(0, 1.0f));
}
/// <summary>
/// 清除獎(jiǎng)品的相關(guān)數(shù)據(jù)和設(shè)置新的顏色
/// </summary>
public void ClearData()
{
grigtData.Clear();
foreach (Transform tr in mTransLs)
{
tr.GetComponent<Image>().color = GetColors();
tr.gameObject.SetActive(false);
}
}
/// <summary>
/// 設(shè)置獎(jiǎng)勵(lì)信息
/// </summary>
/// <param name="text">名稱</param>
/// <param name="point">所占的百分比</param>
/// <param name="gID">該獎(jiǎng)品的ID</param>
public void AddData(string text, float point, int gID)
{
if (point < 0.05f)
{
Debug.LogError("獎(jiǎng)品的概率不能小于5%");
}
if (point >1.0f)
{
Debug.LogError("獎(jiǎng)品的概率不能大于100%");
}
GrifData data = new GrifData();
data.mText = text;
data.point = point;
data.gID = gID;
grigtData.Add(data);
if (mPoints.ContainsKey(gID))
{
// mPoints[gID] = point;
Debug.LogError("物品的ID不能一致,無(wú)法添加到字典");
return;
}
mPoints.Add(gID, point);
checkProbability.Add(point);
}
/// <summary>
/// 設(shè)置獎(jiǎng)品轉(zhuǎn)盤(pán)的面積的大小顯示
/// </summary>
public void SetPriceRange()
{
float total = 0;
for (int i = 0; i < checkProbability.Count; i++)
{
total += checkProbability[i];
}
if (total.ToString() !="1")
{
Debug.LogError("獎(jiǎng)品的概率總和不等于百分百,請(qǐng)從新設(shè)定概率");
return;
}
transform.localEulerAngles = Vector3.zero;
// List<SData> temDate = mData.OrderBy(mData => mData.point).ToList(); //升序排序
//亂序排列
randomData.Clear();
int count = grigtData.Count; //所設(shè)置的獎(jiǎng)品的個(gè)數(shù)
for (int i = 0; i < count; i++)
{
int ra = Random.Range(0, grigtData.Count);
randomData.Add(grigtData[ra]);
grigtData.RemoveAt(ra);
}
if (mListSD.Count > 0)
{
mListSD.Clear(); //先清空
}
float nowAmount = 0;
Text text;
for (int i = 0; i < count; i++) //把設(shè)置了獎(jiǎng)品的顯示出來(lái)
{
Transform tr = mTransLs[i];
tr.gameObject.SetActive(true);
// Debug.Log(ramData[i].mText + "/n");
//因?yàn)槔L制獎(jiǎng)勵(lì)區(qū)域是從轉(zhuǎn)盤(pán)的下面6點(diǎn)順時(shí)針?lè)较蜷_(kāi)始繪制,而指針是在上面9點(diǎn),轉(zhuǎn)盤(pán)是順時(shí)針轉(zhuǎn)動(dòng),加多180度,
//ramData[i].point/2 使得轉(zhuǎn)盤(pán)停下來(lái)時(shí)使得獎(jiǎng)品剛好處于指針的中間
float target = 180 + (nowAmount + randomData[i].point/2) * 360;
if (target > 360)
target -= 360;
text = tr.Find("Text").GetComponent<Text>();
text.text = randomData[i].mText;
GrifInfo grifInfo = new GrifInfo(); //暫時(shí)預(yù)留,發(fā)獎(jiǎng)品不是單倍的時(shí)候有用
grifInfo.mText = text; //暫時(shí)預(yù)留,發(fā)獎(jiǎng)品不是單倍的時(shí)候有用
grifInfo.msg = randomData[i].mText; //暫時(shí)預(yù)留,發(fā)獎(jiǎng)品不是單倍的時(shí)候有用
mListSD.Add(grifInfo); //暫時(shí)預(yù)留,發(fā)獎(jiǎng)品不是單倍的時(shí)候有用
tr.GetComponent<Image>().fillAmount = randomData[i].point;
//這個(gè)是旋轉(zhuǎn)所設(shè)置的獎(jiǎng)品的角度
tr.localEulerAngles = new Vector3(0, 0, -nowAmount * 360); //0.1Amount = 36度
nowAmount += randomData[i].point;
// Debug.Log(" i = " + i + "target = " + target);
randomData[i].angle = target;
randomData[i].mtran = tr.name;
// Debug.Log("target = " + target);
}
}
/// <summary>
/// 設(shè)置獎(jiǎng)品的倍數(shù)
/// </summary>
/// <param name="multiple"></param>
public void SetMultiple(int multiple)
{
foreach (GrifInfo ss in mListSD)
{
if (multiple == 1)
{
ss.mText.text = ss.msg;
}
else
{
ss.mText.text = ss.msg + " X" + multiple;
}
}
}
/// <summary>
/// 獲得結(jié)果(得到概率)
/// </summary>
public void GetResult()
{
float probability = Random.Range(0.0f, 1.0f);
float nowSub = 0;
string testStr = "";
for (int i = 0; i < randomData.Count; i++)
{
nowSub += mPoints[randomData[i].gID]; //該獎(jiǎng)品對(duì)應(yīng)的概率(Amount值)
if (probability < nowSub)
{
tarAngle = randomData[i].angle; //該獎(jiǎng)品停止轉(zhuǎn)動(dòng)時(shí)需要轉(zhuǎn)動(dòng)的角度
tarName = randomData[i].mtran; //該獎(jiǎng)品的名稱
giftID = randomData[i].gID; //ID
testStr ="獎(jiǎng)品名稱 = " + randomData[i].mText + " 獎(jiǎng)品概率 = " + (mPoints[randomData[i].gID] * 100 + " UI上的名稱 = " + tarName + " 獎(jiǎng)品的ID = " + giftID);
Debug.Log(testStr);
break;
}
}
}
private void StartRotate()
{
GetResult();
dialRotate.StartQuan(tarAngle, tarName);
Debug.Log("StartRotate() : tarAngle = " + tarAngle);
}
}
----------------------分割線----------------------
DialRotate.cs
using UnityEngine;
public enum RollType
{
None,
Start, //開(kāi)始轉(zhuǎn)動(dòng)
ConstantSpeed, //勻速運(yùn)動(dòng)
Stop, //停止運(yùn)動(dòng)
}
public class DialRotate : MonoBehaviour {
private RollType nowType = RollType.None;
private float tarAngle; //該獎(jiǎng)品停下來(lái)時(shí)父物體Z軸需要轉(zhuǎn)動(dòng)的角度
/// <summary>
/// 當(dāng)前Z軸的值
/// </summary>
private float nowAngle = 0;
private string grifName;
private float time;//計(jì)時(shí)器
private float speed = 0;
public float angleSpeed = 2;
void Update () {
if (Input.GetMouseButtonDown(1))
{
if (nowType == RollType.ConstantSpeed)
{
nowType = RollType.Stop;
// Debug.Log("tarAngle = " + tarAngle + " nowAngle = " + nowAngle);
tarAngle += nowAngle + 360;
time = 0;
}
}
if (nowType == RollType.Start)
{
time += Time.deltaTime;
float x = angleSpeed * time * time; //這些數(shù)值影響轉(zhuǎn)盤(pán)的轉(zhuǎn)動(dòng)速度,自己看著喜歡調(diào)節(jié)即可
nowAngle -= x;
speed += 4 * time;
transform.localEulerAngles = new Vector3(0, 0, nowAngle);
if (speed > 400)
{
nowType = RollType.ConstantSpeed;
}
}
else if (nowType == RollType.ConstantSpeed)
{
nowAngle -= speed * Time.deltaTime; //勻速旋轉(zhuǎn)
transform.localEulerAngles = new Vector3(0, 0, nowAngle);
}
else if (nowType == RollType.Stop)
{
//速度慢慢變小,轉(zhuǎn)盤(pán)慢慢的慢下來(lái)
speed = Mathf.Lerp(speed, Mathf.Min(speed, tarAngle * 0.25f), Time.deltaTime);
// Debug.Log("speed = " + speed);
if (speed < 5)
{
speed = 5;
}
float angle = speed * Time.deltaTime;
tarAngle -= angle;
nowAngle -= angle;
if (tarAngle < 0)
{
Debug.Log("轉(zhuǎn)盤(pán)停止轉(zhuǎn)動(dòng)");
nowType = RollType.None;
}
else
{
transform.localEulerAngles = new Vector3(0, 0, nowAngle);
}
}
if (nowAngle < -360)
{
nowAngle += 360;
}
}
public void StartQuan(float tarAngle, string giftName)
{
if (nowType != RollType.None)
{
return;
}
grifName = giftName;
this.tarAngle = 360 * 2 - tarAngle;
nowType = RollType.Start;
time = 0;
nowAngle = transform.localEulerAngles.z;
speed = 0;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問(wèn)題和解決思路詳解
這篇文章主要介紹了在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問(wèn)題和解決過(guò)程的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
C#實(shí)現(xiàn)的微信網(wǎng)頁(yè)授權(quán)操作邏輯封裝示例
這篇文章主要介紹了C#實(shí)現(xiàn)的微信網(wǎng)頁(yè)授權(quán)操作邏輯封裝,分析了微信網(wǎng)頁(yè)授權(quán)操作的原理、步驟并給出了C#實(shí)現(xiàn)的網(wǎng)頁(yè)授權(quán)操作邏輯封裝類,需要的朋友可以參考下2016-10-10
利用C#編寫(xiě)一個(gè)Windows服務(wù)程序的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C#編寫(xiě)一個(gè)Windows服務(wù)程序,文中的實(shí)現(xiàn)方法講解詳細(xì),具有一定的參考價(jià)值,感興趣的可以了解一下2023-03-03
C#逐行分元素讀取記事本數(shù)據(jù)并寫(xiě)入數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了C#逐行分元素讀取記事本數(shù)據(jù)并寫(xiě)入數(shù)據(jù)庫(kù)的方法,通過(guò)StreamReader類里的ReadLine()方法實(shí)現(xiàn)逐行讀取的功能,是非常實(shí)用的技巧,需要的朋友可以參考下2014-12-12
C#?多項(xiàng)目打包時(shí)如何將項(xiàng)目引用轉(zhuǎn)為包依賴(最新推薦)
這篇文章主要介紹了C#多項(xiàng)目打包時(shí)如何將項(xiàng)目引用轉(zhuǎn)為包依賴,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-04-04

