Unity3D優化技巧系列五
阿新 • • 發佈:2019-02-04
筆者介紹:姜雪偉,IT公司技術合夥人,IT高階講師,CSDN社群專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D遊戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。
架構設計也是優化的一種,一款遊戲如果沒有一個好的架構,程式出現問題很難做到及時的響應,讀者可以試想一下,如果程式設計的時候只是為了實現功能而實現功能,到頭來就是程式碼越寫越亂,各種功能交織在一起。出現問題後到處找BUG修復,優化就更無從談起了,誰也不希望把即將上線的專案程式碼,重新重構一遍,那還不如重新再做一遍,所以架構設計在遊戲開發中是非常重要的,而且是必須要掌握的技術。下面重點給讀者介紹MVC和FSM架構模式,效果如下所示:
MVC架構模式在前面的優化系列中給讀者提過,下面就詳細的告訴讀者如何編寫程式碼?給讀者詳細的分析一下,拿視窗的切換進行距離,遊戲執行時,首先是創立介面,我們把每個介面作為一個視窗,比如LoginWindow,HeroWindow等。它們也是作為View介面,這樣遊戲中就會出現很多介面的設計,效果如下所示:
下面分析介面的編寫,上文提到的每個UI就是一個Window,也是一個View,這麼多View肯定有自己的共性,我們可以將其定義為基類,基類稱為BaseWindow,程式碼編寫如下所示:
以上是關於窗體的基類,實現了所有窗體需要建立的方法,建立窗體,銷燬窗體,預載入,掩藏 等操作。實行按的具體操作類需要繼承該窗體類,比如LoginWindow的寫法如下所示:namespace Game.View { public abstract class BaseWindow { protected Transform mRoot; protected EScenesType mScenesType; //場景型別 protected string mResName; //資源名 protected bool mResident; //是否常駐 protected bool mVisible = false; //是否可見 //類物件初始化 public abstract void Init(); //類物件釋放 public abstract void Realse(); //視窗控制初始化 protected abstract void InitWidget(); //視窗控制元件釋放 protected abstract void RealseWidget(); //遊戲事件註冊 protected abstract void OnAddListener(); //遊戲事件注消 protected abstract void OnRemoveListener(); //顯示初始化 public abstract void OnEnable(); //隱藏處理 public abstract void OnDisable(); //每幀更新 public virtual void Update(float deltaTime) { } //取得所以場景型別 public EScenesType GetScenseType() { return mScenesType; } //是否已開啟 public bool IsVisible() { return mVisible; } //是否常駐 public bool IsResident() { return mResident; } //顯示 public void Show() { if (mRoot == null) { if (Create()) { InitWidget(); } } if (mRoot && mRoot.gameObject.activeSelf == false) { mRoot.gameObject.SetActive(true); mVisible = true; OnEnable(); OnAddListener(); } } //隱藏 public void Hide() { if (mRoot && mRoot.gameObject.activeSelf == true) { OnRemoveListener(); OnDisable(); if (mResident) { mRoot.gameObject.SetActive(false); } else { RealseWidget(); Destroy(); } } mVisible = false; } //預載入 public void PreLoad() { if (mRoot == null) { if (Create()) { InitWidget(); } } } //延時刪除 public void DelayDestory() { if (mRoot) { RealseWidget(); Destroy(); } } //建立窗體 private bool Create() { if (mRoot) { Debug.LogError("Window Create Error Exist!"); return false; } if (mResName == null || mResName == "") { Debug.LogError("Window Create Error ResName is empty!"); return false; } if (GameMethod.GetUiCamera.transform== null) { Debug.LogError("Window Create Error GetUiCamera is empty! WindowName = " + mResName); return false; } GameObject obj = LoadUiResource.LoadRes(GameMethod.GetUiCamera.transform, mResName); if (obj == null) { Debug.LogError("Window Create Error LoadRes WindowName = " + mResName); return false; } mRoot = obj.transform; mRoot.gameObject.SetActive(false); return true; } //銷燬窗體 protected void Destroy() { if (mRoot) { LoadUiResource.DestroyLoad(mRoot.gameObject); mRoot = null; } } //取得根節點 public Transform GetRoot() { return mRoot; } } }
該類主要是實現整個UI的邏輯編寫,其他的視窗編寫類似。下面編寫Control控制類程式碼的編寫,示例程式碼如下:namespace Game.View { public class LobbyWindow : BaseWindow { public LobbyWindow() { mScenesType = EScenesType.EST_Login; //場景型別 mResName = GameConstDefine.LoadGameLobbyUI; //資源名字 mResident = false; //是否常駐記憶體 } ////////////////////////////繼承介面///////////////////////// //類物件初始化 public override void Init() { EventCenter.AddListener(EGameEvent.eGameEvent_LobbyEnter, Show); EventCenter.AddListener(EGameEvent.eGameEvent_LobbyExit, Hide); } //類物件釋放 public override void Realse() { EventCenter.RemoveListener(EGameEvent.eGameEvent_LobbyEnter, Show); EventCenter.RemoveListener(EGameEvent.eGameEvent_LobbyExit, Hide); } //視窗控制元件初始化 protected override void InitWidget() { mHomepage = mRoot.FindChild("StartMenuManager/StartMenuBtn/Homepage").GetComponent<UIToggle>(); UIGuideCtrl.Instance.AddUiGuideEventBtn(mHomepage.gameObject); mBattle = mRoot.FindChild("StartMenuManager/StartMenuBtn/Battle").GetComponent<UIToggle>(); mMarket = mRoot.FindChild("StartMenuManager/StartMenuBtn/Market").GetComponent<UIToggle>(); mInteraction = mRoot.FindChild("StartMenuManager/StartMenuBtn/Interaction").GetComponent<UIToggle>(); UIGuideCtrl.Instance.AddUiGuideEventBtn(mMarket.gameObject); mDiamondText = mRoot.FindChild("Status/Diamond/Label").GetComponent<UILabel>(); mGoldText = mRoot.FindChild("Status/Gold/Label").GetComponent<UILabel>(); mSettingBtn = mRoot.FindChild("Status/Setting").GetComponent<UIButton>(); UIGuideCtrl.Instance.AddUiGuideEventBtn(mBattle.gameObject); EventDelegate.Add(mHomepage.onChange, OnHomePageChange); EventDelegate.Add(mBattle.onChange, OnBattleChange); EventDelegate.Add(mMarket.onChange, OnMarketChange); EventDelegate.Add(mInteraction.onChange, OnInteractionChange); UIEventListener.Get(mHeadIcon.transform.parent.gameObject).onClick += InfoPersonPress; } private void InfoPersonPress(GameObject go) { GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_PersonalInfo); LobbyCtrl.Instance.AskPersonInfo(); //PresonInfoCtrl.Instance.Enter(); } //視窗控制元件釋放 protected override void RealseWidget() { } //遊戲事件註冊 protected override void OnAddListener() { EventCenter.AddListener(EGameEvent.eGameEent_ChangeMoney, RefreshMoney); EventCenter.AddListener<bool>(EGameEvent.eGameEvent_ReceiveLobbyMsg, NewChat); EventCenter.AddListener(EGameEvent.eGameEvent_AddNewMailReq, NoticeNewMail); EventCenter.AddListener(EGameEvent.eGameEvent_ChangeNickName,ChangeNickName); EventCenter.AddListener(EGameEvent.eGameEvent_ChangeHeadID, ChangeHeadID); EventCenter.AddListener(EGameEvent.eGameEvent_ChangeUserLevel, ChangeLevel); } private void ChangeHeadID() { mHeadIcon.spriteName = GameUserModel.Instance.GameUserHead.ToString(); } //遊戲事件注消 protected override void OnRemoveListener() { EventCenter.RemoveListener(EGameEvent.eGameEent_ChangeMoney, RefreshMoney); EventCenter.RemoveListener<bool>(EGameEvent.eGameEvent_ReceiveLobbyMsg, NewChat); EventCenter.RemoveListener(EGameEvent.eGameEvent_AddNewMailReq, NoticeNewMail); EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeNickName, ChangeNickName); EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeHeadID, ChangeHeadID); EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeUserLevel, ChangeLevel); } //顯示 public override void OnEnable() { } //隱藏 public override void OnDisable() { } public void ChangeUserLevel() { mLevel.text = GameUserModel.Instance.UserLevel.ToString(); } //回撥事件 public void OnHomePageChange() { //todo mLevel.text = GameUserModel.Instance.UserLevel.ToString(); mNickName.text = GameUserModel.Instance.GameUserNick; mHeadIcon.spriteName = GameUserModel.Instance.GameUserHead.ToString(); mGold.text = GameUserModel.Instance.mGameUserGold.ToString(); mDiamond.text = GameUserModel.Instance.mGameUserDmd.ToString(); VipSignLevel.text = "VIP "+GameUserModel.Instance.GameUserVipLevel.ToString(); int level = GameUserModel.Instance.UserLevel; mLevel.text = level.ToString(); LevelConfigInfo leveinfo = ConfigReader.GetLevelInfo(level); if (leveinfo != null) { mExp.text = GameUserModel.Instance.GameUserExp + "/" + leveinfo.LevelUpExp; mExp.transform.parent.GetComponent<UISprite>().fillAmount = GameUserModel.Instance.GameUserExp / leveinfo.LevelUpExp; if (level >= 29 && GameUserModel.Instance.GameUserExp >= leveinfo.LevelUpExp) { level = 30; mLevel.text = level.ToString(); mExp.gameObject.SetActive(false); mExp.transform.parent.GetComponent<UISprite>().fillAmount = 1f; } } if (mHomepage.value) { GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_HomePage); HomePageCtrl.Instance.Enter(); } else { HomePageCtrl.Instance.Exit(); } } public void OnBattleChange() { if (mBattle.value) { GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Battle); BattleCtrl.Instance.Enter(); } else { BattleCtrl.Instance.Exit(); } } public void OnMarketChange() { if (mMarket.value) { GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Market); MarketCtrl.Instance.Enter(); } else { MarketCtrl.Instance.Exit(); } } public void OnInteractionChange() { if (mInteraction.value) { GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Friend); SocialCtrl.Instance.Enter(); } else { SocialCtrl.Instance.Exit(); } } public void MailListBtn(GameObject obj) { mMailBtnBg.SetActive(false); MailCtrl.Instance.Enter(); } } }
public class LoginCtrl : Singleton<LoginCtrl>
{
public void Enter()
{
EventCenter.Broadcast(EGameEvent.eGameEvent_LoginEnter);
}
public void Exit()
{
EventCenter.Broadcast(EGameEvent.eGameEvent_LoginExit);
}
//登陸
public void Login(string account, string pass)
{
}
//登陸錯誤反饋
public void LoginError(int code)
{
}
//接收GateServer資訊
public void RecvGateServerInfo(Stream stream)
{
}
//登陸失敗
public void LoginFail()
{
}
//選擇LoginServer
public void SelectLoginServer(int i)
{
}
//開始遊戲
public void GamePlay()
{
}
}
}
控制類的主要作用是進行一些訊息的傳遞,這也是為了解除模組之間的耦合性,該模組的主要核心是Enter函式和Exit函式。後面繼續程式碼的編寫。。。。