Unity3D優化技巧系列六
阿新 • • 發佈:2019-02-09
筆者介紹:姜雪偉,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; } }
對窗體進行註冊,顯示,隱藏等操作,該函式實現了對遊戲中所有窗體的管理工作。窗體之間如何切換?我們使用了狀態機去編寫邏輯,每個窗體都有自己的狀態類,狀態類也有共性,我們將其抽離出來,實現程式碼如下:
父類實現了後,LoginState的實現如下:namespace Game.GameState { public interface IGameState { GameStateType GetStateType(); void SetStateTo(GameStateType gsType); void Enter(); GameStateType Update(float fDeltaTime); void FixedUpdate(float fixedDeltaTime); void Exit(); } }
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類介面的呼叫。另外,我們編寫的邏輯是不掛在指令碼上的,資源都是動態載入的,後面會告訴讀者如何使用,後面會繼續給讀者講解。。。。。。