ET學習筆記之五星麻將2

前言

其實越看ET的代碼,越覺得自己的知識儲備不夠,好多地方只能淺嘗輒止,這也是半路出家當和尚的無奈。
今天是國慶節,一邊看國慶直播,一邊寫這篇筆記,不禁感嘆我天朝之偉大。
泱泱大國,不容小覷。有幸見證這樣的曠世直播,真是了不起!
胸中澎湃的浩然正氣,似乎無法用文字來描述。
看完直播,對我們的未來也更加期待,雖然我們還需要更加努力,畢竟川普之流還在敵視我們,香港在躁動,臺灣還沒有收復,脫貧尚未完成……
但是我相信,如果我們的技術足夠強大,我們終將Free。
所以爲了得到Free,繼續努力下去。
老實講,川普和天朝開戰真是愚不可及之事,他的政治生涯恐怕會因此黯然失色。

遊戲大廳

上一篇我們已經可以進入遊戲大廳界面了,如下圖所示:
遊戲大廳
我們先來追溯進入遊戲大廳的過程,在KCPUseManage發起連接之前,由ET的事件機制調用了Awake方法:

        private KCPStateManage _mStateManage;
        public void Awake()
        {
            Ins = this;
            _mStateManage= this.GetComponent<KCPStateManage>();
        }

Awake完成了單例模式的同時,也緩存了KCPStateManage的引用,稍後我們會進入該類。在上一篇的LoginAndConnect登錄連接過程中,這個被緩存的引用完成了賦值操作:

 Action<G2C_GateLogin> connectSuccesAction = _mStateManage.ConnectSuccess;//連接成功

該事件在LoginAndConnect最後,登錄成功返回確切消息後又被調用:

                //發起連接成功事件
                connectSuccesAction(g2CLoginGate);

這行代碼實際上調用了KCPStateManage的ConnectSuccess方法:

        //連接成功
        public void ConnectSuccess(G2C_GateLogin g2CGateLogin)
        {
            Log.Debug("連接成功");
            pKCPNetWorkState = KCPNetWorkState.Connect;
            pConnectSuccessCall?.Invoke(g2CGateLogin);
        }

ConnectSuccess方法中有個?號,其實是個空值判定的高級寫法,等價於:

if(pConnectSuccessCall!=null)pConnectSuccessCall.Invoke(g2CGateLogin);

而該事件早就被訂閱了,可以追溯到KCPUseManage被添加的時候,追溯到Init中Game.Scene.AddComponent<KCPUseManage>();//KCP使用組件,因爲AddComponent而觸發ET的AwakeSystem,通過KCPUseManage的Awake又self.AddComponent<KCPLocalizationDispose>();,又觸發KCPLocalizationDispose的Awake,一系列ET事件機制的連鎖反應。
蝴蝶的翅膀輕輕扇動,就在大洋彼岸掀起了龍捲風。
Anyway,通過事件機制pConnectSuccessCall在KCPLocalizationDispose中被訂閱了:

        public void Awake()
        {
            KCPStateManage.Ins.pConnectLostCall += ConnectLostEvent;
            KCPStateManage.Ins.pAgainConnectFailureCall += AgainConnectFailureEvent;

            KCPStateManage.Ins.pStartConnectCall += StartConnectEvent;
            KCPStateManage.Ins.pStartReconnectionCall += StartReconnectionEvent;
            KCPStateManage.Ins.pConnectFailureCall += ConnectFailureEvent;
            KCPStateManage.Ins.pConnectSuccessCall += ConnectSuccessEvent;
            KCPStateManage.Ins.pAgainConnectSuccessCall += AgainConnectSuccessEvent;
        }

實際上訂閱了一大堆KCPStateManage的狀態事件,只要對應的事件觸發,這裏對應的方法就會調用:

        //連接成功
        private void ConnectSuccessEvent(G2C_GateLogin g2CGateLogin)
        {
            UIComponent.GetUiView<LoadingIconPanelComponent>().Hide();
            User user = g2CGateLogin.User;
            Game.Scene.GetComponent<UserComponent>().SetSelfUser(user); ;
            Game.Scene.GetComponent<ToyGameComponent>().StartGame(ToyGameId.Lobby);
            SessionComponent.Instance.Session.AddComponent<HeartbeatComponent>();//添加心跳組件 
        }

連接成功後,先隱藏了負責顯示加載的UI面板LoadingIconPanel,然後獲取用戶User信息並進行設置。
接着通過StartGame方法進入大廳的通道,同時開始心跳。

大廳通道 LobbyAisle

之前已經講過,五星麻將都是通過通道來切換場景的,可以在下圖的位置找到相關代碼:
通道
在執行StartGame(ToyGameId.Lobby);時,最終調用的就是LobbyAisle的StartGame方法:

        public override void StartGame(params object[] objs)
        {
            base.StartGame();
            Log.Debug("進入大廳");
            UIComponent.GetUiView<FiveStarLobbyPanelComponent>().Show();
        }

至此進入大廳的整個流程已經追溯完了。

大廳UI

加載UI以後,首先是要緩存引用:

            ReferenceCollector rc = this.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>();
            mMuChuangViewGo = rc.Get<GameObject>("MuChuangViewGo");
            mRecordPerformanceBtn = rc.Get<GameObject>("RecordPerformanceBtn").GetComponent<Button>();
            mRightBtnViewGo = rc.Get<GameObject>("RightBtnViewGo");
            mUserInfoViewGo = rc.Get<GameObject>("UserInfoViewGo");
            mTopBtnViewGo = rc.Get<GameObject>("TopBtnViewGo");
            mBroadcastViewGo = rc.Get<GameObject>("BroadcastViewGo");
            mLobbyBgClip = rc.Get<AudioClip>("lobbybgMusic");
            
            InitPanel();

後面就是一些UI初始化的操作,比較基礎的知識點,所以我就不囉嗦了。
其中SdkCall是微信開放平臺對應的接口,調用一些社交方面的功能,例如用戶信息、定位、朋友圈等。

燈籠搖晃動畫

其實很多2D遊戲的UI都是帶動畫效果的,這樣顯得整個界面很有生機,五星麻將大廳的燈籠就有隨風飄動的效果,這個其實是很簡單的動畫,我們甚至可以放一個風車在裏面轉動。

public class LanternAnim
    {
        private GameObject _AigletGo;
        public GameObject gameObject;
        public LanternAnim(GameObject go)
        {
            gameObject = go;
            _AigletGo = go.FindChild("AigletGo").gameObject;
            PlayAnim();
        }

        public const float LanternRange = 3.00f;//燈籠的搖晃幅度
        public const float AigletRange = 18.00f;//吊墜的搖晃幅度

        private Vector3 _LanternVector = new Vector3(0, 0, 0);
        private Vector3 _AigletVector = new Vector3(0, 0, 0);
        private static int RangePlus = 1;
        private bool isAnimIn;
        public async void PlayAnim()
        {
            if (isAnimIn)
            {
                return;
            }

            isAnimIn = true;
            while (gameObject.activeInHierarchy)
            {
                
                _LanternVector.z = (float)RandomTool.Random(LanternRange/2, LanternRange) * RangePlus;
                _AigletVector.z = (float)RandomTool.Random(AigletRange/2, AigletRange) * RangePlus;
                gameObject.transform.DOLocalRotate(_LanternVector, 3f);
                _AigletGo.transform.DOLocalRotate(_AigletVector, 3f);
                RangePlus = RangePlus * -1;
                await ETModel.Game.Scene.GetComponent<TimerComponent>().WaitAsync(2000);
            }
            isAnimIn = false;
        }
    }

這個很簡單,用一個協程來調用DOLocalRotate,這是屬於DOTween插件的transform擴展方法。
我們的遊戲如果有在UI上掛燈籠,也完全可以用得上這段代碼。

匹配房間

當點擊大廳燈籠上的匹配房間按鈕時,對應的UI事件就觸發了:

        public void MatchBtnEvent()
        {
            UIComponent.GetUiView<MatchingRoomPanelComponent>().Show();
        }

這時就彈出了匹配房間的面板,如圖所示:
匹配房間面板
這裏的初級場、中級場、高級場是根據配置生成的,這裏同樣使用了協程:

        private async void InitRoomList()
        {
            if (_MatchRoomConfigs==null)
            {
                await RequestMatchRoomConfigs();
            }
            Transform roomItemParent = mRoomItemGo.transform.parent;
            _RoomLists=roomItemParent.CreatorChildAndAddItem<MathRoomItem, MatchRoomConfig>(
                _MatchRoomConfigs);
        }

如果匹配房間配置沒有,就會請求服務器:

        //想服務器請求 所有匹配房間配置
        private RepeatedField<MatchRoomConfig> _MatchRoomConfigs;
        private async Task RequestMatchRoomConfigs()
        {
            L2C_GetMatchRoomConfigs l2CGetMatchRoomConfigs = (L2C_GetMatchRoomConfigs)await SessionComponent.Instance.Call(new C2L_GetMatchRoomConfigs() { ToyGameId = ToyGameId.CardFiveStar });
            _MatchRoomConfigs = l2CGetMatchRoomConfigs.MatchRoomConfigs;
        }

RepeatedField相當於是List列表,從服務器得到這些配置列表後,就可以創建對應的按鈕了。

        public void EnterRoom()
        {
            CardFiveStarAisle.MatchingEnterRoom(mData.MatchRoomId,mData.RoomConfigs);
        }

點擊對應的按鈕就會進入對應MatchRoomId的房間,也就是上面的EnterRoom方法,該方法是和按鈕事件綁定的,這屬於是基本操作了。下面開始進入到房間,房間的玩法邏輯已經不再大廳範疇,請看後文。

創建房間

點擊創建房間那個燈籠,就觸發了下面的方法:

        public void CreateRoomBtnEvent()
        {
            UIComponent.GetUiView<CreateRoomPanelComponent>().ShowCraterRoomPanel(ShowCraterRoomPanelType.NormalCraterRoom, CardFiveStarAisle.CreateRoom);
        }

彈出對應的窗口,如下圖所示:
創建房間

加入房間

加入房間同上,都是些UI按鈕事件,邏輯簡單,這裏就不贅述了。如果這方面有疑惑,應該學習下對應的教程。當然,大廳的功能是比較全面的,全部寫下來會很囉嗦,那樣的話可以錄製視頻教程了。
所以,在這裏就此打住好了,已經起到拋磚引玉的效果了,看看源代碼都可以順藤摸瓜了。
之前有做過麻將遊戲的開發,所以遊戲邏輯對於我來說,都十分熟悉了。不太熟悉的只是ET框架而已,所以五星麻將就寫到這一篇作爲結束篇,如果大家想學習麻將的邏輯,請評論點贊。
設置一個Flag在這裏好了,評論或點贊數超過100的話,我就把五星麻將完整的麻將邏輯梳理出來。
麻將遊戲對於我個人來說,完全是得心應手的事情,這是我不願意寫下去的原因,成長收益不高。但是大家想學習這方面的知識的話,我也是個助人爲樂的人,所以根據大家的意願來吧。
時間是寶貴的,祝大家國慶節快樂,願祖國繁榮昌盛,早日實現中華民族的偉大復興!
我們這些程序猿也要繼續努力啊!

作者的話

Alt

如果喜歡可以點贊支持一下,謝謝鼓勵!如果有什麼疑問可以給我留言,有錯漏的地方請批評指證!
技術難題?加入開發者聯盟:566189328(QQ付費羣)提供有限技術探討,以及,心靈雞湯Orz!
當然,不需要技術探討也歡迎加入進來,在這裏劈柴、遛狗、聊天、擼貓!( ̄┰ ̄*)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章