zoukankan      html  css  js  c++  java
  • Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑

    Hi,之前有同学说要我把源码发出来,那我就把半成品源码的链接放在每篇文件的最后,有兴趣的话可以查阅参考,有问题可以跟我私信,也可以关注我的个人公众号,互相交流嘛。当然,代码也是在不断的持续改进中~

    上期我们实现了叫地主功能,不过遗留了一个小功能:叫地主完成以后,要显示地主的3张牌,这期首先弥补这块的功能;

    接着我们要进入开发出牌逻辑的开发阶段,好了,废话不多说,继续我们斗地主开发之旅~

    地主牌的显示

    我们在玩家界面的顶部中间位置,放置一个新的GameObject,命名为BidCards,用来记录3张地主牌的显示位置。

    所以我们重构了CardManager中的发牌方法,在给地主发牌同时,生成地主牌的实例,放在BidCards相应位置:

        /// <summary>
        /// 发牌堆上的牌(如果现在不是抢地主阶段,发普通牌,如果是,发地主牌)
        /// </summary>
        /// <returns></returns>
        private IEnumerator DealHeapCards(bool ifForBid)
        {
            //显示牌堆
            heapPos.gameObject.SetActive(true);
            playerHeapPos.ToList().ForEach(s => { s.gameObject.SetActive(true); });
    
            var cardNamesNeeded = ifForBid
                ? cardNames.Skip(cardNames.Length - 3).Take(3)  //如果是抢地主牌,取最后3张
                : cardNames.Take(cardNames.Length - 3);         //如果首次发牌
    
            //计算每张地主牌的位置
            int cardIndex = 0;
            var width = (bidCards.GetComponent<RectTransform>().sizeDelta.x - 20) / 3;
            var centerBidPos = Vector3.zero;
            var leftBidPos = centerBidPos - Vector3.left * width;
            var rightBidPos = centerBidPos + Vector3.left * width;
            List<Vector3> bidPoss = new List<Vector3> { leftBidPos, centerBidPos, rightBidPos };
            foreach (var cardName in cardNamesNeeded)
            {
                //给当前玩家发一张牌
                Players[termCurrentIndex].AddCard(cardName);
    
                var cover = Instantiate(coverPrefab, heapPos.position, Quaternion.identity, heapPos.transform);
                cover.GetComponent<RectTransform>().localScale = Vector3.one;
                //移动动画,动画结束后自动销毁
                var tween = cover.transform.DOMove(playerHeapPos[termCurrentIndex].position, 0.3f);
                tween.OnComplete(() => Destroy(cover));
    
                yield return new WaitForSeconds(1 / dealCardSpeed);
    
                //如果给地主发牌
                if (ifForBid)
                {
                    //显示地主牌
                    var bidcard = Instantiate(cardPrefab, bidCards.transform.TransformPoint(bidPoss[cardIndex]), Quaternion.identity, bidCards.transform);
                    bidcard.GetComponent<Card>().InitImage(new CardInfo(cardName));
                    bidcard.GetComponent<RectTransform>().localScale = Vector3.one * 0.3f;
                }
                else
                {
                    //下一个需要发牌者
                    SetNextPlayer();
                }
    
                cardIndex++;
            }
    
            //隐藏牌堆
            heapPos.gameObject.SetActive(false);
            playerHeapPos[0].gameObject.SetActive(false);
    
            //发普通牌
            if (!ifForBid)
            {
                //显示玩家手牌
                ShowPlayerSelfCards();
                StartBiding();
            }
            //发地主牌
            else
            {
                if (Players[bankerIndex] is PlayerSelf)
                {
                    //显示玩家手牌
                    ShowPlayerSelfCards();
                }
                StartFollowing();
            }
        }
    View Code

    好的,我们地主牌显示已经没有问题了,接下来,我们要实现出牌回合逻辑

    出牌回合功能实现

    出牌回合其实跟叫地主回合类似,也是可以抽象出3种方法:进入出牌阶段、出牌、不出(比较进入叫地主阶段、叫地主、不叫地主);

    因此,我们参照叫地主的逻辑,再实现出牌逻辑:

    调整Player基类

    添加开始出牌ToFollowing、出牌ForFollow、不出NotFollow:

    • ToFollowing:进入自己回合,关闭其他人的倒计时,进入自己的倒计时阶段;
    • ForFollow:关闭自己的倒计时,然后将选择的牌添加到出牌区域,跳出自己回合;
    • NotFollow:关闭自己的倒计时,跳出自己回合;
        /// <summary>
        /// 开始出牌
        /// </summary>
        public virtual void ToFollowing()
        {
            isMyTerm = true;
    
            //关闭倒计时
            StopCountDown(CountDownTypes.Follow);
    
            //开始倒计时
            StartCountDown(CountDownTypes.Follow);
        }
        /// <summary>
        /// 出牌
        /// </summary>
        public void ForFollow()
        {
            //关闭倒计时
            StopCountDown(CountDownTypes.Follow);
    
            //选择的牌,添加到出牌区域
            var selectedCards = cardInfos.Where(s => s.isSelected).ToList();
            var offset = 5;
            for (int i = 0; i < selectedCards.Count(); i++)
            {
                var card = Instantiate(prefabSmall, smallCardPos.position + Vector3.right * offset * i, Quaternion.identity, smallCardPos.transform);
                card.GetComponent<RectTransform>().localScale = Vector3.one * 0.3f;
                card.GetComponent<Image>().sprite = Resources.Load("Images/Cards/" + selectedCards[i].cardName, typeof(Sprite)) as Sprite;
                card.transform.SetAsLastSibling();
    
                smallCards.Add(card);
            }
            cardInfos = cardInfos.Where(s => !s.isSelected).ToList();
    
            CardManager._instance.ForFollow();
            isMyTerm = false;
        }
        /// <summary>
        /// 不出
        /// </summary>
        public void NotFollow()
        {
            //关闭倒计时
            StopCountDown(CountDownTypes.Follow);
    
            CardManager._instance.NotFollow();
            isMyTerm = false;
        }
        /// <summary>
        /// 销毁出牌对象
        /// </summary>
        public void DropAllSmallCards()
        {
            smallCards.ForEach(Destroy);
            smallCards.Clear();
        }
    View Code

    调整PlayerSelf类

    实现ToFollowing:

    调用基类的ToFollowing,并显示出牌按钮以供玩家选择

        /// <summary>
        /// 开始出牌
        /// </summary>
        public override void ToFollowing()
        {
            base.ToFollowing();
            CardManager._instance.SetFollowButtonActive(true);
        }
    View Code

    调整PlayerOther类

    模拟出牌,随机选择除手牌中的一张

        void Update()
        {
            //如果当前是自己回合,模拟对手叫牌
            if (isMyTerm)
            {
                if (CardManager._instance.cardManagerState == CardManagerStates.Bid)
                {
                    if (Input.GetKeyDown(KeyCode.Q))    //叫牌
                    {
                        ForBid();
                    }
                    if (Input.GetKeyDown(KeyCode.W))    //不叫
                    {
                        NotBid();
                    }
                }
                if (CardManager._instance.cardManagerState == CardManagerStates.Playing)
                {
                    if (Input.GetKeyDown(KeyCode.Q))    //出牌
                    {
                        var rd1 = Random.Range(0, cardInfos.Count);
                        cardInfos[rd1].isSelected = true;
    
                        ForFollow();
                    }
                    if (Input.GetKeyDown(KeyCode.W))    //不出
                    {
                        NotFollow();
                    }
                }
            }
        }
    View Code

    调整CardManager

    实现卡牌管理对玩家出牌的控制:

    • 发完地主牌以后,开始出牌阶段,由地主先出牌;
    • 玩家选择出牌后,将上轮玩家的出牌堆清空,并将选择的牌添加到自己的出牌堆,轮转到下个玩家;
    • 玩家选择不出牌,将上轮玩家的出牌堆清空,轮转到下个玩家;
        /// <summary>
        /// 开始出牌阶段
        /// </summary>
        private void StartFollowing()
        {
            cardManagerState = CardManagerStates.Playing;
            //地主先出牌
            Players[bankerIndex].ToFollowing();
        }
        /// <summary>
        /// 玩家出牌
        /// </summary>
        public void ForFollow()
        {
            SetFollowButtonActive(false);
    
            //上轮玩家出牌清空
            Players[(termCurrentIndex + Players.Length - 1) % 3].DropAllSmallCards();
            if (Players[termCurrentIndex] is PlayerSelf)
                ShowPlayerSelfCards();
    
            SetNextPlayer();
            Players[termCurrentIndex].ToFollowing();
        }
        /// <summary>
        /// 玩家不出
        /// </summary>
        public void NotFollow()
        {
            SetFollowButtonActive(false);
    
            //上轮玩家出牌清空
            Players[(termCurrentIndex + Players.Length - 1) % 3].DropAllSmallCards();
    
            SetNextPlayer();
            Players[termCurrentIndex].ToFollowing();
        }
    View Code

    代码整理

    现在我们的代码具有一定的规模了,为了方便更好的管理,把现有的代码重新整理一下,并进行功能分类,比如:

        

    总结

    嗯,今天到此为止,我们再来测试验证下,当然,目前只是实现了出牌的功能,没有对牌力进行校验和出牌的控制,对手玩家随机模拟出牌,尚未加入AI。我们以后逐步去实现~来看看这期的效果吧~

    资源

    项目源码

  • 相关阅读:
    leetcode 122. Best Time to Buy and Sell Stock II
    leetcode 121. Best Time to Buy and Sell Stock
    python 集合(set)和字典(dictionary)的用法解析
    leetcode 53. Maximum Subarray
    leetcode 202. Happy Number
    leetcode 136.Single Number
    leetcode 703. Kth Largest Element in a Stream & c++ priority_queue & minHeap/maxHeap
    [leetcode]1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree
    正则表达式
    十种排序算法
  • 原文地址:https://www.cnblogs.com/lizzie-xhu/p/7794466.html
Copyright © 2011-2022 走看看