100个 Unity小游戏系列六 -Unity 抽奖游戏专题四 翻卡游戏

一、演示效果

二、知识点讲解

2.1 布局

cs 复制代码
  void CreateItems()
        {
            reward_data_list = reward_data_list ?? new List<RewardData>();
            reward_data_list.Clear();


            for (int i = 0; i < ItemCount; i++)
            {

                GameObject item;
                if (i + 1 <= itemParent.childCount)
                {
                    item = itemParent.GetChild(i).gameObject;
                }
                else
                {
                    item = Instantiate(itemParent.GetChild(0).gameObject, itemParent);
                }

                item.transform.localPosition = initPosArr[i];
                item.transform.localScale = Vector3.one;
                var cardGraphics = item.transform.Find("Graphics").GetComponent<RectTransform>();

                RefreshCardData(cardGraphics, false, rewardDatas[i]);
                SetCardOpen(false, item.GetComponent<Button>(), true, rewardDatas[i]);
            }

            StartAnim(rewardDatas);
        }

/// <summary>
        /// 明牌,洗牌动画
        /// </summary>
        private void StartAnim(RewardData[] rewardsArr)
        {
            CardSelectable = false;

            if (rewardsArr.Length != itemParent.childCount)
            {
                Debug.LogErrorFormat("rewards length is not equals cards count:{0}", itemParent.childCount);
                return;
            }

            isSwapCard = true;
            var seqAnim = DOTween.Sequence();
            seqAnim.AppendInterval(2f);
            seqAnim.AppendCallback(() =>
            {
                int overCount = itemParent.childCount;
                for (int i = 0; i < itemParent.childCount; i++)
                {
                    SetCardOpen(false, itemParent.GetChild(i).GetComponent<Button>(), false, null, 0.2f, () =>
                    {
                        //所有卡片翻回去之后开始洗牌
                        if (--overCount <= 0)
                        {
                            List<int> cardsList = new List<int>();

                            for (int childIndex = 0; childIndex < itemParent.childCount; childIndex++)
                            {
                                cardsList.Add(childIndex);
                            }


                            SwapCards(cardsList, 10, () =>
                            {
                                RefreshCardADState(false);
                                CardSelectable = true;
                            });
                        }
                    });
                }
            });
        }

2.2 转动逻辑

cs 复制代码
 private void SwapCards(List<int> cardsList, int swapCount, Action onComplete)
        {
            if (swapCount <= 0)
            {
                onComplete?.Invoke();
                return;
            }

            SwapCardAnim(cardsList, () =>
            {
                ListRandom(cardsList);
                SwapCards(cardsList, --swapCount, onComplete);
            });
        }

        public static void ListRandom<T>(List<T> sources)
        {
            int index;
            T temp;
            for (int i = 0; i < sources.Count; i++)
            {
                index = UnityEngine.Random.Range(0, sources.Count);
                if (index != i)
                {
                    temp = sources[i];
                    sources[i] = sources[index];
                    sources[index] = temp;
                }
            }
        }
        /// <summary>
        /// 洗牌动画
        /// </summary>
        /// <param name="onSwapOver"></param>
        private void SwapCardAnim(List<int> cardsindexList, Action onSwapOver)
        {
            if (itemParent.childCount % 2 != 0)
            {
                Debug.LogError("cardsRoot 卡片个数不能为奇数");
                return;
            }

            int moveMission = itemParent.childCount;
            TweenCallback onMoveOver = () =>
            {
                if (--moveMission <= 0)
                {
                    onSwapOver?.Invoke();
                }
            };
            for (int i = 0; i < cardsindexList.Count; i += 2)
            {
                var indexA = cardsindexList[i];
                var indexB = cardsindexList[i + 1];
                var cardA = itemParent.GetChild(indexA);
                var cardB = itemParent.GetChild(indexB);
                float moveDuration = Vector2.Distance(initPosArr[indexA], initPosArr[indexB]) / 1500;
                moveDuration = Mathf.Clamp(moveDuration, 0, 0.18f);

                cardA.DOLocalMove(initPosArr[indexB], moveDuration).onComplete = onMoveOver;
                cardB.DOLocalMove(initPosArr[indexA], moveDuration).onComplete = onMoveOver;
            }
        }

        private void SetCardOpen(bool isUser, Button cardBt, bool isOpen, RewardData reward = null, float duration = 0.2f, Action onCardAnimOver = null)
        {
            if (isOpen && reward == null)
            {
                Debug.LogError("翻卡传入奖励数据为null");
                return;
            }
            if (isUser && !CardSelectable)
            {
                return;
            }
            CardSelectable = false;
            int texIndex = 0;
            int colorIndex = 0;
            string tmStr = string.Empty;
            Vector3 halfRotate = new Vector3(0, 90, 0);
            if (isOpen)
            {
                texIndex = reward.type;
                colorIndex = reward.type - 1;
                tmStr = reward.amount.ToString();
                halfRotate.y = 270;
            }

            cardBt.interactable = !isOpen;

            var card = cardBt.transform;
            var cardGraphics = card.Find("Graphics").GetComponent<RectTransform>();

            var seqAnim = DOTween.Sequence();
            seqAnim.Append(cardGraphics.DOLocalRotate(halfRotate, duration).SetEase(Ease.Linear));
            seqAnim.AppendCallback(() =>
            {
                RefreshCardData(cardGraphics, isOpen, reward);
            });
            seqAnim.Append(cardGraphics.DOLocalRotate(halfRotate + Vector3.up * 90, duration).SetEase(Ease.Linear));
            seqAnim.onComplete = () =>
            {
                if (!isUser)
                {
                    //CardSelectable = true;
                    onCardAnimOver?.Invoke();
                }
            };
            if (isUser)
            {
                card.SetSiblingIndex(itemParent.childCount);
                //float moveDuration = Vector2.Distance(card.transform.localPosition, Vector3.zero) / 400;
                //moveDuration = Mathf.Clamp(moveDuration, 0, 0.4f);
                //card.DOMove(Vector3.zero, moveDuration);
                //card.DOScale(1.4f, moveDuration).onComplete = () =>
                //{
                //    var moveSeq = DOTween.Sequence();
                //    moveSeq.AppendInterval(1.0f);
                //    moveSeq.AppendCallback(() =>
                //    {
                //        var smallCard = smallCardsRoot.GetChild(CurClaimIndex);
                //        moveDuration = Mathf.Clamp(Vector2.Distance(card.position, smallCard.position) / 10, 0, 0.4f);
                //        card.DOScale(smallCard.GetComponent<RectTransform>().sizeDelta.x / card.GetComponent<RectTransform>().sizeDelta.x, moveDuration);
                //        card.DOMove(smallCard.position, moveDuration).onComplete = () =>
                //        {
                //            CardSelectable = true;
                //            GF.Sound.PlaySound("poker_end.wav", false);

                //            //加奖励
                //            GF.UserData.ClaimReward(UserDataType.LuckpokerRedpacket, reward, GF.UserData.GameUIForm.gameMainView.levelSocreTxt.transform);
                //            onCardAnimOver?.Invoke();
                //        };
                //    });
                //};


                CardSelectable = true;
                onCardAnimOver?.Invoke();
            }
        }

三 、完整代码逻辑

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

相关推荐
科技圈快迅11 小时前
鸿蒙游戏体验手册:四种能力从性能到玩法逐一解锁
游戏
wjql214 小时前
绝区零诺姆配队推荐 绝区零诺姆怎么配队
游戏
河南花仙子科技21 小时前
复盘蓄力精进迭代|花仙子科技召开 2026 年 Q2 季度复盘总结大会
科技·游戏
生活爱好者!1 天前
NAS还能玩游戏?部署一款 WebGL 3D 赛车小游戏
游戏·docker·容器·玩游戏
丁小未1 天前
基于MVVM框架的XUUI 扩展的UI管理系统教程
unity·mvvm·ui框架·xuui·ui管理器
丁小未2 天前
基于MVVM框架的XUUI HelloWorld 新手教程
unity·性能优化·c#·游戏引擎
丁小未2 天前
基于MVVM框架的XUUI MoreComplex案例
unity·c#
EQ-雪梨蛋花汤2 天前
【Unity笔记】VR 一体机画面锯齿、模型边缘闪烁、接缝抖动排查:MSAA、Mipmap、Render Scale、Z-Fighting 全流程记录
笔记·unity·vr
松树戈2 天前
【Godot4精进之路】03~Godot编辑器常用界面介绍
编辑器·游戏引擎·godot
YigAin2 天前
Unity Spine 资源出现白边的解决办法
unity·游戏引擎·spine