Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)

来源:互联网 发布:网络股票龙头股票 编辑:程序博客网 时间:2024/06/01 08:26

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

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

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

http://blog.sina.com.cn/s/blog_175dc3f8a0102xgxi.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgxg.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgxd.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgww.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwv.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwu.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwt.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwe.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwj.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwi.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwd.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwc.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwb.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgwa.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgw6.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgw7.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtz.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgty.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtx.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtw.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtu.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtt.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgts.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtr.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtq.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtp.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgto.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtn.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgtk.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsh.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsg.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsf.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgse.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsd.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsc.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgsb.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgs3.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgs0.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgr4.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgqc.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgqb.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgqa.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgpp.html
http://blog.sina.com.cn/s/blog_175dc3f8a0102xgpo.html

地主牌的显示

我们在玩家界面的顶部中间位置,放置一个新的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();        }    }
复制代码

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

出牌回合功能实现

出牌回合其实跟叫地主回合类似,也是可以抽象出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();    }
复制代码

调整PlayerSelf类,实现ToFollowing

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

复制代码
    /// <summary>    /// 开始出牌    /// </summary>    public override void ToFollowing()    {        base.ToFollowing();        CardManager._instance.SetFollowButtonActive(true);    }
复制代码

调整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();                }            }        }    }
复制代码

调整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();    }
复制代码

代码整理

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

    

总结

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