任务31:前端-将三个玩家的手牌发送到客户端并显示在牌桌

本节的内容都在前端完成。这节课前端增加了新的所有牌面的图集资源:

Atlas.zip (1.09KB)

HandCard&PlayCard.zip (2.11KB)

上一节,服务端向前端玩家发送了手牌:

前端玩家收到自己的手牌数据:

前端添加接受消息的Actor_GameStartHandCards_NttHandler

本地玩家把服务端传来的手牌添加到handCards中,HandCardsComponent组件中的AddCards方法中有CardsSpriteUpdate来更新桌面上手牌的显示。

//显示牌背面或者手牌
handCards.Appear();
//添加与更新本地玩家的手牌
if (gamer.UserID == LandRoomComponent.LocalGamer.UserID)
{
    //本地玩家添加手牌
    Card[] Tcards = new Card[message.HandCards.Count];
    for (int i = 0; i < message.HandCards.Count; i++)
    {
        Tcards[i] = message.HandCards[i];
    }
    handCards.AddCards(Tcards);
}
else
{
    //设置其他玩家手牌数
    handCards.SetHandCardsNum(gamerCardNum.Num);
}

本节后面有HandCardsComponent组件中有Appear方法。

因为本地玩家是handCards的UI,而另两个玩家是poker的UI,所以用 ?.

public void Appear()
{
      _poker?.SetActive(true);
      _handCards?.SetActive(true);
}

Actor_GameStartHandCards_NttHandler完整代码。

\Assets\Model\Landlords\Handler\Actor_GameStartHandCards_NttHandler.cs

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

namespace ETModel
{
    [MessageHandler]
    public class Actor_GameStartHandCards_NttHandler : AMHandler<Actor_GameStartHandCards_Ntt>
    {
        protected override async ETTask Run(ETModel.Session session, Actor_GameStartHandCards_Ntt message)
        {
            UI uiRoom = Game.Scene.GetComponent<UIComponent>().Get(LandUIType.LandRoom);
            LandRoomComponent room = uiRoom.GetComponent<LandRoomComponent>();

            //初始化玩家UI
            foreach (GamerCardNum gamerCardNum in message.GamersCardNum)
            {
                Gamer gamer = room.GetGamer(gamerCardNum.UserID);
                LandlordsGamerPanelComponent gamerUI = gamer.GetComponent<LandlordsGamerPanelComponent>();
                gamerUI.GameStart();

                HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>();
                if (handCards != null)
                {
                    handCards.Reset();
                }
                else
                {
                    //Log.Debug("没有可以复用的HandCardsComponent,创建一个。");
                    handCards = gamer.AddComponent<HandCardsComponent, GameObject>(gamerUI.Panel);
                }

                //显示牌背面或者手牌
                handCards.Appear();
                //添加与更新本地玩家的手牌
                if (gamer.UserID == LandRoomComponent.LocalGamer.UserID)
                {
                    //本地玩家添加手牌
                    Card[] Tcards = new Card[message.HandCards.Count];
                    for (int i = 0; i < message.HandCards.Count; i++)
                    {
                        Tcards[i] = message.HandCards[i];
                    }
                    handCards.AddCards(Tcards);
                }
                else
                {
                    //设置其他玩家手牌数
                    handCards.SetHandCardsNum(gamerCardNum.Num);
                }
            }

            //显示牌桌UI
            GameObject desk = uiRoom.GameObject.Get<GameObject>("Desk");
            desk.SetActive(true);
            GameObject lordPokers = desk.Get<GameObject>("LordPokers");

            //重置地主牌
            Sprite lordSprite = CardHelper.GetCardSprite("None");
            for (int i = 0; i < lordPokers.transform.childCount; i++)
            {
                lordPokers.transform.GetChild(i).GetComponent<Image>().sprite = lordSprite;
            }

            LandRoomComponent uiRoomComponent = uiRoom.GetComponent<LandRoomComponent>();
            
            //设置初始倍率
            uiRoomComponent.SetMultiples(1);

            await ETTask.CompletedTask;
        }
    }
}

添加手牌组件HandCardsComponent

SetHandCardsNum方法:另两位玩家只有一个卡背,上面显示目前还有多少张牌

AddCards方法:添加牌到桌面手牌

PopCards方法:出牌后,更新桌面手牌

CardsSpriteUpdate方法:更新桌面上手牌的显示

Sort方法:对桌面手牌的左右排序和遮挡的显示层级

HandCardsComponent完整代码 \Assets\Model\Landlords\Component\HandCardsComponent.cs

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

namespace ETModel
{
    [ObjectSystem]
    public class HandCardsComponentAwakeSystem : AwakeSystem<HandCardsComponent, GameObject>
    {
        public override void Awake(HandCardsComponent self, GameObject panel)
        {
            self.Awake(panel);
        }
    }

    public class HandCardsComponent : Component
    {
        public const string HANDCARD_NAME = "HandCard";
        public const string PLAYCARD_NAME = "PlayCard";

        private readonly Dictionary<string, GameObject> cardsSprite = new Dictionary<string, GameObject>();
        private readonly List<Card> handCards = new List<Card>();
        private readonly List<Card> playCards = new List<Card>();

        private GameObject _poker;
        private GameObject _handCards;
        private Text _pokerNum;

        public GameObject Panel { get; private set; }
        public Identity AccessIdentity { get; set; }

        public void Awake(GameObject panel)
        {
            this.Panel = panel;
            _poker = this.Panel.Get<GameObject>("Poker");
            _handCards = this.Panel.Get<GameObject>("HandCards");
            _pokerNum = _poker?.GetComponentInChildren<Text>();

            //加载AB包
            ResourcesComponent resourcesComponent = Game.Scene.GetComponent<ResourcesComponent>();
            resourcesComponent.LoadBundle($"{HANDCARD_NAME}.unity3d");
            resourcesComponent.LoadBundle($"{PLAYCARD_NAME}.unity3d");
            resourcesComponent.LoadBundle($"{CardHelper.ATLAS_NAME}.unity3d");
        }

        public override void Dispose()
        {
            if (this.IsDisposed)
            {
                return;
            }

            base.Dispose();

            Reset();
        }

        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            ClearHandCards();
            ClearPlayCards();
        }

        /// <summary>
        /// 显示玩家游戏UI
        /// </summary>
        public void Appear()
        {
            _poker?.SetActive(true);
            _handCards?.SetActive(true);
        }

        /// <summary>
        /// 隐藏玩家游戏UI
        /// </summary>
        public void Hide()
        {
            _poker?.SetActive(false);
            _handCards?.SetActive(false);
        }

        /// <summary>
        /// 获取卡牌精灵
        /// </summary>
        /// <param name="card"></param>
        /// <returns></returns>
        public GameObject GetSprite(Card card)
        {
            GameObject cardSprite;
            if(cardsSprite.TryGetValue(card.GetName(), out cardSprite))
            {
                return cardSprite;
            }
            Log.Debug("没找到这张卡牌!"+card.GetName());
            return cardSprite;
        }

        /// <summary>
        /// 设置手牌数量
        /// </summary>
        /// <param name="num"></param>
        public void SetHandCardsNum(int num)
        {
            _pokerNum.text = num.ToString();
        }

        /// <summary>
        /// 添加多张牌
        /// </summary>
        /// <param name="cards"></param>
        public void AddCards(Card[] cards)
        {
            for (int i = 0; i < cards.Length; i++)
            {
                AddCard(cards[i]);
            }
            CardsSpriteUpdate(handCards, 50.0f);
        }

        /// <summary>
        /// 出牌后更新玩家手牌
        /// </summary>
        /// <param name="cards"></param>
        public void PopCards(Card[] cards)
        {
            //ClearPlayCards();  //造成重复删除,先注释掉

            for (int i = 0; i < cards.Length; i++)
            {
                PopCard(cards[i]);
                Log.Debug("更新一张牌:"+cards[i].GetName());
            }
            CardsSpriteUpdate(playCards, 25.0f);
            CardsSpriteUpdate(handCards, 50.0f);

            //同步剩余牌数
            GameObject poker = this.Panel.Get<GameObject>("Poker");
            if (poker != null)
            {
                Text pokerNum = poker.GetComponentInChildren<Text>();
                pokerNum.text = (int.Parse(pokerNum.text) - cards.Length).ToString();
            }
        }

        /// <summary>
        /// 清空手牌
        /// </summary>
        public void ClearHandCards()
        {
            ClearCards(handCards);
        }

        /// <summary>
        /// 清空出牌
        /// </summary>
        public void ClearPlayCards()
        {
            ClearCards(playCards);
        }

        /// <summary>
        /// 卡牌精灵更新
        /// </summary>
        public void CardsSpriteUpdate(List<Card> cards, float interval)
        {
            if (cards.Count == 0)
            {
                return;
            }

            Sort(cards);

            float width = GetSprite(cards[0]).GetComponent<RectTransform>().sizeDelta.x;
            float startX = -((cards.Count - 1) * interval) / 2;
            for (int i = 0; i < cards.Count; i++)
            {
                RectTransform rect = GetSprite(cards[i]).GetComponent<RectTransform>();
                rect.anchoredPosition = new Vector2(startX + (i * interval), rect.anchoredPosition.y);
            }
        }

        /// <summary>
        /// 清空卡牌
        /// </summary>
        /// <param name="cards"></param>
        private void ClearCards(List<Card> cards)
        {
            for (int i = cards.Count - 1; i >= 0; i--)
            {
                Card card = cards[i];
                Log.Debug("删除卡牌"+card.GetName());
                GameObject cardSprite = cardsSprite[card.GetName()];
                cardsSprite.Remove(card.GetName());
                cards.Remove(card);
                UnityEngine.Object.Destroy(cardSprite);
            }
        }

        /// <summary>
        /// 卡牌排序
        /// </summary>
        /// <param name="cards"></param>
        private void Sort(List<Card> cards)
        {
            CardHelper.Sort(cards);

            //卡牌精灵层级排序
            //Log.Debug("重设卡牌精灵层级");
            for (int i = 0; i < cards.Count; i++)
            {
                //Log.Debug("卡牌精灵" + cards[i].GetName());
                GetSprite(cards[i]).transform.SetSiblingIndex(i);
            }
        }

        /// <summary>
        /// 添加卡牌
        /// </summary>
        /// <param name="card"></param>
        private void AddCard(Card card)
        {
            GameObject handCardSprite = CreateCardSprite(HANDCARD_NAME, card.GetName(), this.Panel.Get<GameObject>("HandCards").transform);
            handCardSprite.GetComponent<HandCardSprite>().Poker = card;
            cardsSprite.Add(card.GetName(), handCardSprite);
            handCards.Add(card);
        }

        /// <summary>
        /// 出牌
        /// </summary>
        /// <param name="card"></param>
        private void PopCard(Card card)
        {
            //移除手牌
            //因为对象并不是完全一致,不能用Contains来查找
            foreach(var a in handCards)
            {
                if(a.Equals(card))
                {
                    Log.Debug("pop删除卡牌"+a.GetName());
                    GameObject handCardSprite = GetSprite(a);
                    cardsSprite.Remove(a.GetName());
                    handCards.Remove(a);
                    UnityEngine.Object.Destroy(handCardSprite);
                    break;
                }
            }

            GameObject playCardSprite = CreateCardSprite(PLAYCARD_NAME, card.GetName(), this.Panel.Get<GameObject>("PlayCards").transform);
            cardsSprite.Add(card.GetName(), playCardSprite);
            playCards.Add(card);
        }

        /// <summary>
        /// 创建卡牌精灵
        /// </summary>
        private GameObject CreateCardSprite(string prefabName, string cardName, Transform parent)
        {
            GameObject cardSpritePrefab = (GameObject)Game.Scene.GetComponent<ResourcesComponent>().GetAsset($"{prefabName}.unity3d", prefabName);
            GameObject cardSprite = UnityEngine.Object.Instantiate(cardSpritePrefab);
            
            cardSprite.name = cardName;
            cardSprite.layer = LayerMask.NameToLayer("UI");
            cardSprite.transform.SetParent(parent.transform, false);

            Sprite sprite = CardHelper.GetCardSprite(cardName);
            cardSprite.GetComponent<Image>().sprite = sprite;

            return cardSprite;
        }
    }
}

添加牌面比较和手牌排序的CardHelper

\Assets\Model\Landlords\Other\CardHelper.cs

using System.Collections.Generic;
using UnityEngine;

namespace ETModel
{
    public static class CardHelper
    {
        //卡牌图集预设名称
        public const string ATLAS_NAME = "Atlas";

        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="cards"></param>
        public static void Sort(List<Card> cards)
        {
            for (int i = cards.Count; i > 0; i--)
            {
                for (int j = 0; j < i - 1; j++)
                {
                    //先按照权重降序,再按花色升序
                    if (-CompareTo((int)cards[j].CardWeight, (int)cards[j + 1].CardWeight) * 2 +
                    CompareTo((int)cards[j].CardSuits, (int)cards[j + 1].CardSuits) > 0)
                    {
                        Card temp = cards[j];
                        cards[j] = cards[j + 1];
                        cards[j + 1] = temp;
                    }
                }
            }
        }

        /// <summary>
        /// int比较
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareTo(int a, int b)
        {
            int result;
            if (a > b)
            {
                result = 1;
            }
            else if (a < b)
            {
                result = -1;
            }
            else
            {
                result = 0;
            }
            return result;
        }

        /// <summary>
        /// 获取卡牌精灵
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cardName"></param>
        /// <returns></returns>
        public static Sprite GetCardSprite(string cardName)
        {
            GameObject atlas = (GameObject)ETModel.Game.Scene.GetComponent<ResourcesComponent>().GetAsset($"{ATLAS_NAME}.unity3d", ATLAS_NAME);
            return atlas.Get<Sprite>(cardName);
        }
    }
}

本节需要增加的bundles

所有牌的Atlas资源

PlayCard卡背资源

HandCard手牌资源

要挂上HandCardSprite脚本,本文后面有添加这个类


以上记得添加atlas.unity3d,handcard.unity3d,playCard.unity3d的bundle

其它新添加的类与原来一些类新添加的方,没什么含量:

LandRoomComponent增加属性和方法 \Assets\Model\Landlords\LandUI\LandRoom\LandRoomComponent.cs

增加倍数显示ui的属性

private Text multiples;

awake中获取multiples

multiples = rc.Get<GameObject>("Multiples").GetComponent<Text>();

前端显示本局牌的倍数方法

public void SetMultiples(int multiples)
{
    this.multiples.gameObject.SetActive(true);
    this.multiples.text = multiples.ToString();
}

public void ResetMultiples()
{
    this.multiples.gameObject.SetActive(false);
    this.multiples.text = "1";
}

LandlordsGamerPanelComponent增加方法 \Assets\Model\Landlords\Component\LandlordsGamerPanelComponent.cs

清空三个玩家信息界面上的准备状态提示

/// <summary>
/// 游戏开始
/// </summary>
public void GameStart()
{
      ResetPrompt();
}

EventIdType增加属性 \Assets\ET.Core\Base\Event\EventIdType.cs

选中与取消选中桌面上的牌的事件定义

public const string SelectHandCard = "SelectHandCard";
public const string CancelHandCard = "CancelHandCard";

添加游戏中牌的类,区别与消息体中牌的类Card

\Assets\ET.Core\Landlords\Card.cs

namespace ETModel
{
    /// <summary>
    /// 参考Unit类
    /// </summary>
    public partial class Card
    {
        public static Card Create(int weight, int suits)
        {
            Card card = new Card();
            card.CardWeight = weight;
            card.CardSuits = suits;
            return card;
        }

        public bool Equals(Card other)
        {
            return this.CardWeight == other.CardWeight && this.CardSuits == other.CardSuits;
        }

        /// <summary>
        /// 获取卡牌名
        /// </summary>
        /// <returns></returns>
        public string GetName()
        {
            return this.CardSuits == (int)Suits.None ? ((Weight)this.CardWeight).ToString() : $"{((Suits)this.CardSuits).ToString()}{((Weight)this.CardWeight).ToString()}";
        }
    }

}

添加前端斗地主需要的各种枚举定义类Type

\Assets\ET.Core\Landlords\Type.cs

namespace ETModel
{
    /// <summary>
    /// 房间等级
    /// </summary>
    public enum RoomLevel
    {
        Lv100   //100底分局
    }
    
    /// <summary>
    /// 身份
    /// </summary>
    public enum Identity
    {
        None,
        Farmer,     //平民
        Landlord    //地主
    }

    /// <summary>
    /// 出牌类型
    /// </summary>
    public enum CardsType
    {
        None,
        JokerBoom,          //王炸
        Boom,               //炸弹
        OnlyThree,          //三张
        ThreeAndOne,        //三带一
        ThreeAndTwo,        //三带二
        Straight,           //顺子 五张或更多的连续单牌
        DoubleStraight,     //双顺 三对或更多的连续对牌
        TripleStraight,     //三顺 二个或更多的连续三张牌
        Double,             //对子
        Single              //单牌
    }

    public enum Weight
    {
        Three,      //3
        Four,       //4
        Five,       //5
        Six,        //6
        Seven,      //7
        Eight,      //8
        Nine,       //9
        Ten,        //10
        Jack,       //J
        Queen,      //Q
        King,       //K
        One,        //A
        Two,        //2
        SJoker,     //小王
        LJoker,     //大王
    }

    public enum Suits
    {
        Club,    //梅花
        Diamond, //方块
        Heart,   //红心
        Spade,   //黑桃
        None
    }
}

添加给桌面每张手牌挂的脚本HandCardSprite

\Assets\Model\Landlords\Other\HandCardSprite.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

namespace ETModel
{
    public class HandCardSprite : MonoBehaviour
    {
        public Card Poker { get; set; }
        private bool isSelect;

        void Start()
        {
            EventTrigger eventTrigger = gameObject.AddComponent<EventTrigger>();
            eventTrigger.triggers = new List<EventTrigger.Entry>();
            EventTrigger.Entry clickEntry = new EventTrigger.Entry();
            clickEntry.eventID = EventTriggerType.PointerClick;
            clickEntry.callback = new EventTrigger.TriggerEvent();
            clickEntry.callback.AddListener(new UnityAction<BaseEventData>(OnClick));
            eventTrigger.triggers.Add(clickEntry);
        }

        public void OnClick(BaseEventData data)
        {
            float move = 50.0f;
            if (isSelect)
            {
                move = -move;
                Game.EventSystem.Run(EventIdType.CancelHandCard, Poker);
            }
            else
            {
                Game.EventSystem.Run(EventIdType.SelectHandCard, Poker);
            }
            RectTransform rectTransform = this.GetComponent<RectTransform>();
            rectTransform.anchoredPosition += Vector2.up * move;
            isSelect = !isSelect;
        }
    }
}

运行上节的服务端,前端打包输出,Release中运行三个客户端,分别登录点准备游戏后,桌面上显示手牌:

posted @ 2023-02-16 14:35  Domefy  阅读(37)  评论(0编辑  收藏  举报