任务34:后端-用出牌缓存组件对牌桌上的出牌进行缓存

对比前面讲到的手牌组件,牌库组件:

牌库组件DeckComponent(扩展类中):用于创建一副牌,洗牌,从牌库发牌

  • public static void Shuffle 洗牌
  • public static Card Deal 从牌库发牌

  • public static void AddCard 向牌库中添加牌

  • private static void CreateDeck 创建一副牌

手牌组件HandCardsComponent(扩展类中):用于管理玩家手牌和出牌后从手牌移除

  • public static Card[] GetAll 获取所有手牌

  • public static void AddCard 向手牌中添加牌

  • public static void PopCard 出牌后从手牌移除

出牌缓存组件DeskCardsCacheComponent(扩展类中):用于操作和管理游戏过程中的出牌和地主牌缓存

  • public static int GetTotalWeight 获取出牌总权值

  • public static Card[] GetAll 获取牌桌所有出牌

  • public static Card Deal 出牌缓存中发牌,只有一开始的地主牌是从出牌缓存发牌

  • public static void AddCard 向出牌缓存添加牌

  • public static void Clear 清空出牌缓存

添加出牌缓存组件DeskCardsCacheComponent

\Server\ET.Core\Landlords\Component\Map\DeskCardsCacheComponent.cs

看他缓存了什么能明白此组件用途:

        //出牌缓存
        public readonly List<Card> library = new List<Card>();

        //地主牌
        public readonly List<Card> LordCards = new List<Card>();

        //出牌缓存的总牌数
        public int CardsCount { get { return this.library.Count; } }

        //当前最大牌型
        public CardsType Rule { get; set; }

        //牌桌上最小的牌
        public int MinWeight { get { return (int)this.library[0].CardWeight; } }

完整DeskCardsCacheComponent.cs

using System.Collections.Generic;

namespace ETModel
{
    public class DeskCardsCacheComponent : Component
    {
        //出牌缓存
        public readonly List<Card> library = new List<Card>();

        //地主牌
        public readonly List<Card> LordCards = new List<Card>();

        //出牌缓存的总牌数
        public int CardsCount { get { return this.library.Count; } }

        //当前最大牌型
        public CardsType Rule { get; set; }

        //牌桌上最小的牌
        public int MinWeight { get { return (int)this.library[0].CardWeight; } }

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

            base.Dispose();

            library.Clear();
            LordCards.Clear();
            Rule = CardsType.None;
        }
    }
}

添加出牌缓存组件DeskCardsCacheComponent扩展类

\Server\Hotfix\Landlords\System\DeskCardsCacheComponentSystem.cs

namespace ETModel
{
    public static class DeskCardsCacheComponentSystem
    {
        /// <summary>
        /// 获取总权值
        /// </summary>
        public static int GetTotalWeight(this DeskCardsCacheComponent self)
        {
            //本节还没讲到先注释
            //return CardHelper.GetWeight(self.library.ToArray(), self.Rule);
            return 0;
        }

        /// <summary>
        /// 获取牌桌所有牌
        /// </summary>
        public static Card[] GetAll(this DeskCardsCacheComponent self)
        {
            return self.library.ToArray();
        }

        /// <summary>
        /// 发牌
        /// 玩家的牌都是由手牌组件发牌的,牌库中只有一开始的地主牌是从牌库发牌(借用)
        /// </summary>
        public static Card Deal(this DeskCardsCacheComponent self)
        {
            Card card = self.library[self.CardsCount - 1];
            self.library.Remove(card);
            return card;
        }

        /// <summary>
        /// 向牌库中添加牌
        /// </summary>
        public static void AddCard(this DeskCardsCacheComponent self, Card card)
        {
            self.library.Add(card);
        }

        /// <summary>
        /// 清空牌桌
        /// </summary>
        public static void Clear(this DeskCardsCacheComponent self)
        {
            DeckComponent deck = self.GetParent<Entity>().GetComponent<DeckComponent>();
            while (self.CardsCount > 0)
            {
                Card card = self.library[self.CardsCount - 1];
                self.library.Remove(card);
                deck.AddCard(card);
            }

            self.Rule = CardsType.None;
        }
    }
}

在RoomSystem的GameStart方法中添加出牌缓存组件

\Server\Hotfix\Landlords\System\RoomSystem.cs

//手牌缓存组件
self.AddComponent<DeskCardsCacheComponent>();

Room实体中去掉上节两个暂用地主牌属性

\Server\ET.Core\Landlords\Entity\Map\Room.cs

        //暂用地主牌属性
        // public readonly List<Card> LordCards = new List<Card>();
        // public readonly List<Card> LordCache = new List<Card>();

GameControllerComponentSystem组件扩展类去掉上节暂用存发地主牌方法

下面代码注释中有“//@@@”,说明如何用出牌组件替换上节的暂用存发地主牌方法,新的完整GameControllerComponentSystem代码

\Server\Hotfix\Landlords\System\GameControllerComponentSystem.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ETModel;

namespace ETHotfix
{
    [ObjectSystem]
    public class GameControllerComponentAwakeSystem : AwakeSystem<GameControllerComponent, RoomConfig>
    {
        public override void Awake(GameControllerComponent self, RoomConfig config)
        {
            self.Awake(config);
        }
    }

    public static class GameControllerComponentSystem
    {
        public static void Awake(this GameControllerComponent self, RoomConfig config)
        {
            self.Config = config;
            self.BasePointPerMatch = config.BasePointPerMatch;
            self.Multiples = config.Multiples;
            self.MinThreshold = config.MinThreshold;
        }

        /// <summary>
        /// 准备开始游戏
        /// </summary>
        public static void StartGame(this GameControllerComponent self)
        {
            Room room = self.GetParent<Room>();
            Gamer[] gamers = room.gamers;

            //初始玩家开始状态
            foreach (var _gamer in gamers)
            {
                if (_gamer.GetComponent<HandCardsComponent>() == null)
                {
                    _gamer.AddComponent<HandCardsComponent>();
                }
            }
            
            GameControllerComponent gameController = room.GetComponent<GameControllerComponent>();
            //洗牌发牌
            gameController.DealCards();

            List<GamerCardNum> gamersCardNum = new List<GamerCardNum>();
            Array.ForEach(gamers, (g) =>
            {
                HandCardsComponent handCards = g.GetComponent<HandCardsComponent>();
                //重置玩家身份
                handCards.AccessIdentity = Identity.None;
                //重置玩家手牌数
                gamersCardNum.Add(new GamerCardNum()
                {
                    UserID = g.UserID,
                    Num = g.GetComponent<HandCardsComponent>().GetAll().Length
                });
            });

            //发送玩家手牌和玩家手牌数
            foreach (var _gamer in gamers)
            {
                ActorMessageSenderComponent actorProxyComponent = Game.Scene.GetComponent<ActorMessageSenderComponent>();
                ActorMessageSender actorProxy = actorProxyComponent.Get(_gamer.CActorID);
                
                actorProxy.Send(new Actor_GameStartHandCards_Ntt()
                {
                    HandCards = To.RepeatedField(_gamer.GetComponent<HandCardsComponent>().GetAll()),
                    GamersCardNum = To.RepeatedField(gamersCardNum)
                });
            }

            //随机先手玩家
            gameController.RandomFirstAuthority();
            
            Log.Info($"房间{room.Id}开始游戏");
        }

        /// <summary>
        /// 轮流发牌
        /// </summary>
        public static void DealCards(this GameControllerComponent self)
        {
            Room room = self.GetParent<Room>();

            //牌库洗牌
            room.GetComponent<DeckComponent>().Shuffle();

            //玩家轮流发牌
            Gamer[] gamers = room.gamers;
            int index = 0;
            for (int i = 0; i < 51; i++)
            {
                if (index == 3)
                {
                    index = 0;
                }
                self.DealTo(gamers[index].UserID);
                index++;
            }

            //发地主牌
            for (int i = 0; i < 3; i++)
            {
                //出牌缓存一开始是空的可借用一下来缓存本局所发的地主牌
                self.DealTo(room.Id);
            }
            self.Multiples = self.Config.Multiples;
        }

        /// <summary>
        /// 发牌
        /// </summary>
        public static void DealTo(this GameControllerComponent self, long id)
        {
            Room room = self.GetParent<Room>();
            Card card = room.GetComponent<DeckComponent>().Deal();
            
            //@@@ 替换了上节暂用存地主牌方法
            //如果id为roomid,说明是发地主牌,不是给玩家id发牌
            if (id == room.Id) 
            {
                DeskCardsCacheComponent deskCardsCache = room.GetComponent<DeskCardsCacheComponent>();
                deskCardsCache.AddCard(card);
                deskCardsCache.LordCards.Add(card);
            }
            else
            {
                foreach (var gamer in room.gamers)
                {
                    if (id == gamer.UserID)
                    {
                        gamer.GetComponent<HandCardsComponent>().AddCard(card);
                        break;
                    }
                }
            }
           
        }

        /// <summary>
        /// 给牌桌发地主牌
        /// </summary>
        public static void CardsOnTable(this GameControllerComponent self, long id)
        {
            Room room = self.GetParent<Room>();
            DeskCardsCacheComponent deskCardsCache = room.GetComponent<DeskCardsCacheComponent>();
            OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();
            HandCardsComponent handCards = room.GetGamerFromUserID(id).GetComponent<HandCardsComponent>();

            orderController.Start(id);

            for (int i = 0; i < 3; i++)
            { 
                //@@@ 替换了上节暂用发地主牌方法,出牌缓存中移除了地主牌缓存
                Card card = deskCardsCache.Deal(); 
                //将地主牌添加到地主玩家的手牌
                handCards.AddCard(card);
            }

            //更新玩家身份
            foreach (var gamer in room.gamers)
            {
                Identity gamerIdentity = gamer.UserID == id ? Identity.Landlord : Identity.Farmer;
                self.UpdateInIdentity(gamer, gamerIdentity);
            }

            //广播地主消息
            room.Broadcast(new Actor_SetLandlord_Ntt() { UserID = id, LordCards = To.RepeatedField(deskCardsCache.LordCards) });

            //广播地主先手出牌消息(先手显示出牌交互操作界面)
            room.Broadcast(new Actor_AuthorityPlayCard_Ntt() { UserID = id, IsFirst = true });
        }

        /// <summary>
        /// 更新身份
        /// </summary>
        public static void UpdateInIdentity(this GameControllerComponent self, Gamer gamer, Identity identity)
        {
            gamer.GetComponent<HandCardsComponent>().AccessIdentity = identity;
        }

        /// <summary>
        /// 场上的所有牌回到牌库中
        /// </summary>
        public static void BackToDeck(this GameControllerComponent self)
        {
            Room room = self.GetParent<Room>();
            DeckComponent deckComponent = room.GetComponent<DeckComponent>();
            
            //回收玩家手牌
            foreach (var gamer in room.gamers)
            {
                HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>();
                while (handCards.CardsCount > 0)
                {
                    Card card = handCards.library[handCards.CardsCount - 1];
                    handCards.PopCard(card);
                    deckComponent.AddCard(card);
                }
            }
        }

        /// <summary>
        /// 随机先手玩家
        /// </summary>
        public static void RandomFirstAuthority(this GameControllerComponent self)
        {
            Room room = self.GetParent<Room>();
            OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>();
            Gamer[] gamers = room.gamers;

            int index = RandomHelper.RandomNumber(0, gamers.Length);
            long firstAuthority = gamers[index].UserID;
            orderController.Init(firstAuthority);

            //广播先手抢地主玩家
            room.Broadcast(new Actor_AuthorityGrabLandlord_Ntt() { UserID = firstAuthority });
        }

    }
}

我们可以理出思路,发牌过程中:

  • 如果地主牌是先发到出牌缓存,完成抢地主确定地主玩家后,从出牌缓存中取出地主牌发到地主玩家手牌,并构建消息发到客户端地主玩家。
  • 如果玩家牌是发到玩家手牌组件,游戏开始时,从手牌组件中取出玩家手牌构建消息发到客户端局内玩家。

这样我们在本节就添加好了出牌缓存组件并用到了地主牌的缓存也发地主牌,下一节开始讲游戏过程中的出牌操作,才是出牌缓存组件的主阵地

 

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