1. 程式人生 > >unity開發抽獎系統

unity開發抽獎系統

這段時間工作比較空閒,想做個抽獎系統,發現網上的抽獎系統看不懂,然後自己做了一個可以隨意定義獎品概率,不管什麼時候停下來指標最終都會轉到指定的獎品哪。。。

廢話不多說,動手一步一步來。

這個抽獎系統就使用了兩張圖片,一個指標,一個圓形的圖片。

然後做一個預製體,圖片就是圓形圖片,image type選擇filled,fill amount控制這個圖片的面積大小,同時也是該圖片的概率,Text元件是該獎品的名稱。

再接下來就做一下介面佈局的工作

Bg就是那個灰色的圖片,Rotate是個空物體,用來掛在指令碼的(DialRotate.cs和Slot.cs),cloneParent也是個空物體,作為預製體的父物體,要注意的是cloneParent中心那個藍色的圓圈要和Rotate的藍色的圈的位置一致,介面佈局工作完成。

接下來到程式碼了,Slot.cs指令碼,一開始會例項化獎品,K鍵和L鍵可以隨意修改獎品名稱,概率(這裡概率做了限制,需要使用的自己修改一下程式碼即可),空格鍵會隨機丟擲物品,並且開始旋轉,滑鼠右鍵是停止轉動(想什麼時候停下來都行,最後都會得到所丟擲的物體)DialRotate.cs指令碼用於處理旋轉的。這兩個指令碼涉及到一些數學計算,慢慢理解即可。

以下是這個工程的指令碼,需要的話直接複製黏貼即可使用

Slot.cs

 

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;   

public class Slot : MonoBehaviour {

    private DialRotate dialRotate;      
    /// <summary>
    /// 獎品資料
    /// </summary>
    private class GrifData
    { 
     /// <summary>
    /// 獎品的名稱
    /// </summary>
        public string mText;
        /// <summary>
        /// 圖片的Amount值
        /// </summary>
        public float point;
        /// <summary>
        /// 獎品停留在指標時父物體要旋轉的角度
        /// </summary>
        public float angle;
        /// <summary>
        /// 該獎品對應UI面板上的名稱
        /// </summary>
        public string mtran;
        /// <summary>
        /// 該獎品的ID
        /// </summary>
        public int gID;
    }
     /// <summary>
     /// 獎品的描述資訊
     /// </summary>
    private class GrifInfo
    {
        public Text mText;
        public string msg;
    }

    private List<GrifInfo> mListSD = new List<GrifInfo>();
    /// <summary>
    /// 獎品的id和概率對應
    /// </summary>
    private Dictionary<int, float> mPoints = new Dictionary<int, float>();
    /// <summary>
    /// 用於儲存獎品資訊(順序排列)(獎品的id,名稱,所佔的百分比)
    /// </summary>
    private List<GrifData> grigtData = new List<GrifData>();
    /// <summary>
    /// 這個也是用於儲存獎品資訊,不過是亂序排列(獎品的id,名稱,所佔的百分比)
    /// </summary>
    private List<GrifData> randomData = new List<GrifData>();
    /// <summary>
    /// 20種獎品的Transform,(最多20個不用的獎勵)
    /// </summary>
    private List<Transform> mTransLs = new List<Transform>();

    private List<Color> mColors = new List<Color>();

    private Transform cloneParent;
    private GameObject clonePrefab;
    /// <summary>
    /// 抽獎停止時父物體轉動的角度
    /// </summary>
    public float tarAngle;
    /// <summary>
    /// 該獎品對應UI面板上的名稱
    /// </summary>
    public string tarName;
    public int giftID;
    /// <summary>
    /// 用於檢驗概率有沒有為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 測試修改獎品,概率
        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("薯條", 0.3f, 1);
            AddData("漢堡", 0.1f, 2);
            AddData("炸雞", 0.2f, 4);
            AddData("啤酒", 0.05f, 5);
            AddData("可樂", 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("薯條", 0.3f, 1);
        AddData("漢堡", 0.1f, 2);
        AddData("炸雞", 0.2f, 4);
        AddData("啤酒", 0.05f, 5);
        AddData("可樂", 0.15f, 6);
        AddData("烤肉", 0.2f, 7);
        SetPriceRange();
    }
     /// <summary>
     /// 獲得隨機顏色
     /// </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>
    /// 清除獎品的相關資料和設定新的顏色
    /// </summary>
    public void ClearData()
    {
        grigtData.Clear();
        foreach (Transform tr in mTransLs)
        {
            tr.GetComponent<Image>().color = GetColors();
            tr.gameObject.SetActive(false);
        }
    }
    /// <summary>
    /// 設定獎勵資訊
    /// </summary>
    /// <param name="text">名稱</param>
    /// <param name="point">所佔的百分比</param>
    /// <param name="gID">該獎品的ID</param>
    public void AddData(string text, float point, int gID)
    {
        if (point < 0.05f)
        {
            Debug.LogError("獎品的概率不能小於5%");
        }
        if (point >1.0f)
        {
            Debug.LogError("獎品的概率不能大於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不能一致,無法新增到字典");
            return;
        }
        mPoints.Add(gID, point);
        checkProbability.Add(point);
    }
    /// <summary>
    /// 設定獎品轉盤的面積的大小顯示
    /// </summary>
    public void SetPriceRange()
    {
        float total = 0;
        for (int i = 0; i < checkProbability.Count; i++)
        {
            total += checkProbability[i];
        }
        if (total.ToString() !="1")
        {
            Debug.LogError("獎品的概率總和不等於百分百,請從新設定概率");
            return;
        }
        transform.localEulerAngles = Vector3.zero;                           
       //  List<SData> temDate = mData.OrderBy(mData => mData.point).ToList(); //升序排序
        //亂序排列
        randomData.Clear();                            
        int count = grigtData.Count;   //所設定的獎品的個數
        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++)     //把設定了獎品的顯示出來
        {
            Transform tr = mTransLs[i];
            tr.gameObject.SetActive(true);
           // Debug.Log(ramData[i].mText + "/n");
            //因為繪製獎勵區域是從轉盤的下面6點順時針方向開始繪製,而指標是在上面9點,轉盤是順時針轉動,加多180度,
            
            //ramData[i].point/2 使得轉盤停下來時使得獎品剛好處於指標的中間                                              
            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(); //暫時預留,發獎品不是單倍的時候有用
            grifInfo.mText = text;              //暫時預留,發獎品不是單倍的時候有用
            grifInfo.msg = randomData[i].mText;    //暫時預留,發獎品不是單倍的時候有用
            mListSD.Add(grifInfo);              //暫時預留,發獎品不是單倍的時候有用
            tr.GetComponent<Image>().fillAmount = randomData[i].point;  
            //這個是旋轉所設定的獎品的角度
            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>
    /// 設定獎品的倍數
    /// </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>
    /// 獲得結果(得到概率)
    /// </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];     //該獎品對應的概率(Amount值)
            if (probability < nowSub)
            {
                tarAngle = randomData[i].angle;  //該獎品停止轉動時需要轉動的角度
                tarName = randomData[i].mtran;   //該獎品的名稱
                giftID = randomData[i].gID;      //ID
                testStr ="獎品名稱 = " + randomData[i].mText + "  獎品概率 = " + (mPoints[randomData[i].gID] * 100 + "  UI上的名稱 = " + tarName + "  獎品的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,  //開始轉動
    ConstantSpeed, //勻速運動
    Stop,   //停止運動
}

public class DialRotate : MonoBehaviour {

    private RollType nowType = RollType.None;     
    private float tarAngle;  //該獎品停下來時父物體Z軸需要轉動的角度
    /// <summary>
    /// 當前Z軸的值
    /// </summary>
    private float nowAngle = 0;
    private string grifName;
    private float time;//計時器
    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; //這些數值影響轉盤的轉動速度,自己看著喜歡調節即可
            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;   //勻速旋轉
            transform.localEulerAngles = new Vector3(0, 0, nowAngle);    
        } 
        else if (nowType == RollType.Stop)
        {
            //速度慢慢變小,轉盤慢慢的慢下來
            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("轉盤停止轉動");
                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;      
    }
}

-------------------------------------------------完畢---------------------