1. 程式人生 > >Unity3D優化技巧系列六

Unity3D優化技巧系列六

筆者介紹:姜雪偉,IT公司技術合夥人,IT高階講師,CSDN社群專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D遊戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。

繼續MVC程式碼的封裝工作,上一節封裝到了Control模組,我們現在很多的窗體,如何管理?這需要我們設計一個管理類去管理所有的窗體,下面給讀者展示如何編寫WindowManager類,程式碼如下:

namespace Game.View
{
   //場景型別
    public enum EScenesType
    {
        EST_None,
        EST_Login,
        EST_Play,
    }

   //窗體型別
    public enum EWindowType
    {
        EWT_LoginWindow, //登入
        EWT_UserWindow, //使用者
        EWT_LobbyWindow,
        EWT_BattleWindow,
        EWT_RoomWindow,
        EWT_HeroWindow,
    }

    public class WindowManager : Singleton<WindowManager>
    {
        public WindowManager()
        {
            mWidowDic = new Dictionary<EWindowType, BaseWindow>();

            mWidowDic[EWindowType.EWT_LoginWindow] = new LoginWindow();
            mWidowDic[EWindowType.EWT_UserWindow] = new UserInfoWindow();
            mWidowDic[EWindowType.EWT_LobbyWindow] = new LobbyWindow();
            mWidowDic[EWindowType.EWT_BattleWindow] = new BattleWindow();
            mWidowDic[EWindowType.EWT_RoomWindow] = new RoomWindow();
            mWidowDic[EWindowType.EWT_HeroWindow] = new HeroWindow();
        }

        public BaseWindow GetWindow(EWindowType type)
        {
            if (mWidowDic.ContainsKey(type))
                return mWidowDic[type];

            return null;
        }

        public void Update(float deltaTime)
        {
            foreach (BaseWindow pWindow in mWidowDic.Values)
            {
                if (pWindow.IsVisible())
                {
                    pWindow.Update(deltaTime);
                }
            }
        }

        public void ChangeScenseToPlay(EScenesType front)
        {
            foreach (BaseWindow pWindow in mWidowDic.Values)
            {
                if (pWindow.GetScenseType() == EScenesType.EST_Play)
                {
                    pWindow.Init();

                    if(pWindow.IsResident())
                    {
                        pWindow.PreLoad();
                    }
                }
                else if ((pWindow.GetScenseType() == EScenesType.EST_Login) && (front == EScenesType.EST_Login))
                {
                    pWindow.Hide();
                    pWindow.Realse();

                    if (pWindow.IsResident())
                    {
                        pWindow.DelayDestory();
                    }
                }
            }
        }

        public void ChangeScenseToLogin(EScenesType front)
        {
            foreach (BaseWindow pWindow in mWidowDic.Values)
            {
                if (front == EScenesType.EST_None && pWindow.GetScenseType() == EScenesType.EST_None)
                {
                    pWindow.Init();

                    if (pWindow.IsResident())
                    {
                        pWindow.PreLoad();
                    }
                }

                if (pWindow.GetScenseType() == EScenesType.EST_Login)
                {
                    pWindow.Init();

                    if (pWindow.IsResident())
                    {
                        pWindow.PreLoad();
                    }
                }
                else if ((pWindow.GetScenseType() == EScenesType.EST_Play) && (front == EScenesType.EST_Play))
                {
                    pWindow.Hide();
                    pWindow.Realse();

                    if (pWindow.IsResident())
                    {
                        pWindow.DelayDestory();
                    }
                }
            }
        }

        /// <summary>
        /// 隱藏該型別的所有Window
        /// </summary>
        /// <param name="front"></param>
        public void HideAllWindow(EScenesType front)
        {
            foreach (var item in mWidowDic)
            {
                if (front == item.Value.GetScenseType())
                {
                    Debug.Log(item.Key);
                    item.Value.Hide();
                    //item.Value.Realse();
                }
            }
        }

        public void ShowWindowOfType(EWindowType type)
        { 
            BaseWindow window;
            if(!mWidowDic.TryGetValue(type , out window))
            {
                return;
            }
            window.Show();
        }

        private Dictionary<EWindowType, BaseWindow> mWidowDic;
    }
}

對窗體進行註冊,顯示,隱藏等操作,該函式實現了對遊戲中所有窗體的管理工作。窗體之間如何切換?我們使用了狀態機去編寫邏輯,每個窗體都有自己的狀態類,狀態類也有共性,我們將其抽離出來,實現程式碼如下:
namespace Game.GameState
{
    public interface IGameState
    {
        GameStateType GetStateType();
        void SetStateTo(GameStateType gsType);
        void Enter();
        GameStateType Update(float fDeltaTime);
        void FixedUpdate(float fixedDeltaTime);
        void Exit();
    }
}
父類實現了後,LoginState的實現如下:
namespace Game.GameState
{
    class LoginState : IGameState
    {
        GameStateType stateTo;

        GameObject mScenesRoot;
	public LoginState()
	{
	}

        public GameStateType GetStateType()
        {
            return GameStateType.GS_Login;
        }

        public void SetStateTo(GameStateType gs)
        {
            stateTo = gs;
        }

        public void Enter()
        {
            SetStateTo(GameStateType.GS_Continue);
            ResourceUnit sceneRootUnit = ResourcesManager.Instance.loadImmediate(GameConstDefine.GameLogin, ResourceType.PREFAB);
            mScenesRoot = GameObject.Instantiate(sceneRootUnit.Asset) as GameObject;

            LoginCtrl.Instance.Enter();
        
            ResourceUnit audioClipUnit = ResourcesManager.Instance.loadImmediate(AudioDefine.PATH_UIBGSOUND, ResourceType.ASSET);
            AudioClip clip = audioClipUnit.Asset as AudioClip;       

            AudioManager.Instance.PlayBgAudio(clip);

            EventCenter.AddListener<CEvent>(EGameEvent.eGameEvent_InputUserData, OnEvent);
            EventCenter.AddListener<CEvent>(EGameEvent.eGameEvent_IntoLobby, OnEvent);
            EventCenter.AddListener(EGameEvent.eGameEvent_SdkLogOff, SdkLogOff);            
        }

        public void Exit()
        {
            EventCenter.RemoveListener<CEvent>(EGameEvent.eGameEvent_InputUserData, OnEvent);
            EventCenter.RemoveListener<CEvent>(EGameEvent.eGameEvent_IntoLobby, OnEvent);
            EventCenter.RemoveListener(EGameEvent.eGameEvent_SdkLogOff, SdkLogOff);       

            //LoadUiResource.DestroyLoad(mUIRoot);
            LoginCtrl.Instance.Exit();
            GameObject.DestroyImmediate(mScenesRoot);            
        }

        public void FixedUpdate(float fixedDeltaTime)
        {
            
        }

        public GameStateType Update(float fDeltaTime)
        {
            return stateTo;
        }

        public void OnEvent(CEvent evt)
        {
            UIPlayMovie.PlayMovie("cg.mp4", Color.black, 2/* FullScreenMovieControlMode.Hidden*/, 3/*FullScreenMovieScalingMode.Fill*/);
            switch (evt.GetEventId())
            {
                case EGameEvent.eGameEvent_InputUserData:
                    SetStateTo(GameStateType.GS_User);
                    break;
                case EGameEvent.eGameEvent_IntoLobby:
                    GameStateManager.Instance.ChangeGameStateTo(GameStateType.GS_Lobby);
                    break;
            }
        }
    }
}
以上是關於State狀態機的類實現,程式碼如下:
namespace Game.GameState
{
    class LoginState : IGameState
    {
        GameStateType stateTo;

        GameObject mScenesRoot;

       // GameObject mUIRoot;
	
		public LoginState()
		{
		}

        public GameStateType GetStateType()
        {
            return GameStateType.GS_Login;
        }

        public void SetStateTo(GameStateType gs)
        {
            stateTo = gs;
        }

        public void Enter()
        {
            SetStateTo(GameStateType.GS_Continue);
            ResourceUnit sceneRootUnit = ResourcesManager.Instance.loadImmediate(GameConstDefine.GameLogin, ResourceType.PREFAB);
            mScenesRoot = GameObject.Instantiate(sceneRootUnit.Asset) as GameObject;

            LoginCtrl.Instance.Enter();
        
            ResourceUnit audioClipUnit = ResourcesManager.Instance.loadImmediate(AudioDefine.PATH_UIBGSOUND, ResourceType.ASSET);
            AudioClip clip = audioClipUnit.Asset as AudioClip;              
        }
        public void Exit()
        {
            EventCenter.RemoveListener<CEvent>(EGameEvent.eGameEvent_InputUserData, OnEvent);
            EventCenter.RemoveListener<CEvent>(EGameEvent.eGameEvent_IntoLobby, OnEvent);
            
            //LoadUiResource.DestroyLoad(mUIRoot);
            LoginCtrl.Instance.Exit();
            GameObject.DestroyImmediate(mScenesRoot);            
        }

        public void FixedUpdate(float fixedDeltaTime)
        {
            
        }

        public GameStateType Update(float fDeltaTime)
        {
            return stateTo;
        }

        public void OnEvent(CEvent evt)
        {
            UIPlayMovie.PlayMovie("cg.mp4", Color.black, 2/* FullScreenMovieControlMode.Hidden*/, 3/*FullScreenMovieScalingMode.Fill*/);
            switch (evt.GetEventId())
            {
                case EGameEvent.eGameEvent_InputUserData:
                    SetStateTo(GameStateType.GS_User);
                    break;
                case EGameEvent.eGameEvent_IntoLobby:
                    GameStateManager.Instance.ChangeGameStateTo(GameStateType.GS_Lobby);
                    break;
            }
        }
    }
}
在Enter函式中,使用了LoginCtrl類介面的呼叫。另外,我們編寫的邏輯是不掛在指令碼上的,資源都是動態載入的,後面會告訴讀者如何使用,後面會繼續給讀者講解。。。。。。