100个 Unity小游戏系列三 -Unity 抽奖游戏专题一 转盘抽奖游戏

一 、效果展示

二、知识点

2.1 布局需要实现功能

1、转动的根目录为itemSpinRoot

2、创建对应的item

3、每个item转动的角度

2.2 代码

cs 复制代码
public class WheelDialog : UIBase
    {
        [SerializeField] Button btnClick;
        [SerializeField] Button btnClose;
        [SerializeField] Sprite[] itemImgs;

        [SerializeField] Transform itemParent;
        Transform itemSpinRoot;

        [Header("物体数量")][SerializeField] int ItemCount = 8;

        private float item_rangle;

        private RewardData[] rewardDatas;

        protected internal override void OnInit(UIView view)
        {
            base.OnInit(view);

            item_rangle = 360f / ItemCount;

           //转动的根目录为itemSpinRoot
            itemSpinRoot = itemParent.parent;

            btnClick.onClick.RemoveAllListeners();
            btnClick.onClick.AddListener(OnClickSpin);
            btnClose.onClick.RemoveAllListeners();
            btnClose.onClick.AddListener(OnCloseEvent);

            rewardDatas = LuckyManager.Instance.GetDefaultWheelData(ItemCount);
            //创建对应的item
            CreateItems(rewardDatas);
        }

        protected internal override void OnOpen(object userData)
        {
            base.OnOpen(userData);

            ResetWheels();
        }



        private void ResetWheels()
        {

        }

        private void CreateItems(RewardData[] wheel_tb)
        {
            Vector3 init_pos = itemParent.GetChild(0).transform.localPosition;
            if (wheel_tb.Length != ItemCount)
            {
                Debug.LogError("wheel_tb.Count !=  wheel_count !!!");
            }

            for (int i = 0; i < wheel_tb.Length; i++)
            {
                var reward_data = wheel_tb[i];
                var next_rot = Quaternion.Euler(0, 0, i * item_rangle);
                var next_pos = next_rot * init_pos;
                GameObject item;
                if (i + 1 <= itemParent.childCount)
                {
                    item = itemParent.GetChild(i).gameObject;
                }
                else
                {
                    item = Instantiate(itemParent.GetChild(0).gameObject, itemParent);
                }
                //每个item转动的角度
                item.transform.localPosition = next_pos;
                item.transform.localRotation = next_rot;

                var reward_text = item.GetComponentInChildren<TextMeshProUGUI>();
                var reward_img = item.GetComponentInChildren<Image>();
                reward_img.sprite = itemImgs[reward_data.type - 1];
                reward_img.SetNativeSize();
                reward_text.text = string.Format("{0}", reward_data.amount);

                item.GetComponentInChildren<ParticleSystem>().GetComponent<Renderer>().sortingOrder = m_Canvas.sortingOrder + 1;
            }
        }

        private void OnClickSpin()
        {
            if (IsRolling)
            {
                return;
            }

            StartSpin(SpinComplete);
        }

}

三、转动核心逻辑

3.1 知识点

1、DOTween实现转动角度方法实现

public static TweenerCore<float, float, FloatOptions> To(

DOGetter<float> getter,

DOSetter<float> setter,

float endValue,

float duration)

{

return DOTween.ApplyTo<float, float, FloatOptions>(getter, setter, endValue, duration);

}

2、设置转动模式

roll_act.SetEase(GetEase());

3.2 代码

cs 复制代码
 private void StartSpin(Action<RewardData> onSpinCompleted)
        {
            IsRolling = true;
            int rewardId = LuckyManager.Instance.CalculateRewardId(rewardDatas);
            var reward_data = LuckyManager.Instance.GetDataById(rewardDatas, rewardId, out int wheel_index);

            //初始角度
            float cur_angle = itemSpinRoot.localRotation.eulerAngles.z;
            int round_count = UnityEngine.Random.Range(4, 5);
            //最后要转动的角度
            float final_angle = -item_rangle * wheel_index + 360 * round_count;

            float duration = 2.5f;
            // DOTween实现转动角度方法实现1
            var roll_act = DOTween.To(() => cur_angle, (x) => cur_angle = x, final_angle, duration);
           //转动模式设置
            roll_act.SetEase(GetEase());
            roll_act.onUpdate = () =>
            {
                // DOTween实现转动角度方法实现2
                itemSpinRoot.localRotation = Quaternion.Euler(0, 0, cur_angle);
            };
            roll_act.OnComplete(() =>
            {
                IsRolling = false;

                onSpinCompleted.Invoke(reward_data);
            });
        }

四、完整代码

cs 复制代码
using UnityEngine;
using DG.Tweening;
using System;
using UnityEngine.UI;
using TMPro;


namespace Pillow.Lucky
{
    public class WheelDialog : UIBase
    {
        [SerializeField] Button btnClick;
        [SerializeField] Button btnClose;
        [SerializeField] Sprite[] itemImgs;

        [SerializeField] Transform itemParent;
        Transform itemSpinRoot;

        [Header("物体数量")][SerializeField] int ItemCount = 8;

        private float item_rangle;

        private RewardData[] rewardDatas;

        protected internal override void OnInit(UIView view)
        {
            base.OnInit(view);

            item_rangle = 360f / ItemCount;

           //转动的根目录为itemSpinRoot
            itemSpinRoot = itemParent.parent;

            btnClick.onClick.RemoveAllListeners();
            btnClick.onClick.AddListener(OnClickSpin);
            btnClose.onClick.RemoveAllListeners();
            btnClose.onClick.AddListener(OnCloseEvent);

            rewardDatas = LuckyManager.Instance.GetDefaultWheelData(ItemCount);
            //创建对应的item
            CreateItems(rewardDatas);
        }

        protected internal override void OnOpen(object userData)
        {
            base.OnOpen(userData);

            ResetWheels();
        }



        private void ResetWheels()
        {

        }

        private void CreateItems(RewardData[] wheel_tb)
        {
            Vector3 init_pos = itemParent.GetChild(0).transform.localPosition;
            if (wheel_tb.Length != ItemCount)
            {
                Debug.LogError("wheel_tb.Count !=  wheel_count !!!");
            }

            for (int i = 0; i < wheel_tb.Length; i++)
            {
                var reward_data = wheel_tb[i];
                var next_rot = Quaternion.Euler(0, 0, i * item_rangle);
                var next_pos = next_rot * init_pos;
                GameObject item;
                if (i + 1 <= itemParent.childCount)
                {
                    item = itemParent.GetChild(i).gameObject;
                }
                else
                {
                    item = Instantiate(itemParent.GetChild(0).gameObject, itemParent);
                }
                //每个item转动的角度
                item.transform.localPosition = next_pos;
                item.transform.localRotation = next_rot;

                var reward_text = item.GetComponentInChildren<TextMeshProUGUI>();
                var reward_img = item.GetComponentInChildren<Image>();
                reward_img.sprite = itemImgs[reward_data.type - 1];
                reward_img.SetNativeSize();
                reward_text.text = string.Format("{0}", reward_data.amount);

                item.GetComponentInChildren<ParticleSystem>().GetComponent<Renderer>().sortingOrder = m_Canvas.sortingOrder + 1;
            }
        }

        private void OnClickSpin()
        {
            if (IsRolling)
            {
                return;
            }

            StartSpin(SpinComplete);
        }

        private void StartSpin(Action<RewardData> onSpinCompleted)
        {
            IsRolling = true;
            int rewardId = LuckyManager.Instance.CalculateRewardId(rewardDatas);
            var reward_data = LuckyManager.Instance.GetDataById(rewardDatas, rewardId, out int wheel_index);

            //初始角度
            float cur_angle = itemSpinRoot.localRotation.eulerAngles.z;
            int round_count = UnityEngine.Random.Range(4, 5);
            //最后要转动的角度
            float final_angle = -item_rangle * wheel_index + 360 * round_count;

            float duration = 2.5f;
            // DOTween实现转动角度方法实现1
            var roll_act = DOTween.To(() => cur_angle, (x) => cur_angle = x, final_angle, duration);
           //转动模式设置
            roll_act.SetEase(GetEase());
            roll_act.onUpdate = () =>
            {
                // DOTween实现转动角度方法实现2
                itemSpinRoot.localRotation = Quaternion.Euler(0, 0, cur_angle);
            };
            roll_act.OnComplete(() =>
            {
                IsRolling = false;

                onSpinCompleted.Invoke(reward_data);
            });
        }

        void SpinComplete(RewardData rewardData)
        {
            UIManager.Instance.ShowRewardDialog(rewardData, itemImgs);
        }


        private Ease GetEase()
        {
            int index = GetSelectLayoutIndex();

            switch (index)
            {
                case 2:
                    return Ease.OutBack;
                case 3:
                    return Ease.OutQuad;
                case 4:
                    return Ease.OutQuart;
                case 5:
                    return Ease.OutCubic;
                case 6:
                    return Ease.OutCirc;
                case 1:
                default:
                    return Ease.Linear;
            }
        }

    }

}

五、代码链接

https://github.com/lixianjun0903/luckydraw-master.git

相关推荐
charon877815 小时前
UE ARPG | 虚幻引擎战斗系统
游戏引擎
小春熙子16 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Footprint_Analytics17 小时前
Footprint Analytics 助力 Sei 游戏生态增长
游戏·web3·区块链
Sitarrrr19 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧19 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
半盏茶香21 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
逐·風1 天前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i1 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
PandaQue1 天前
《怪物猎人:荒野》游戏可以键鼠直连吗
游戏
代码盗圣1 天前
GODOT 4 不用scons编译cpp扩展的方法
游戏引擎·godot