Unity3D优化技巧系列(五):架构设计

发表于2017-04-08
评论0 787浏览

架构设计也是优化的一种,一款游戏如果没有一个好的架构,程序出现问题很难做到及时的响应,试想一下,如果编程的时候只是为了实现功能而实现功能,到头来就是代码越写越乱,各种功能交织在一起。出现问题后到处找BUG修复,优化就更无从谈起了,谁也不希望把即将上线的项目代码,重新重构一遍,那还不如重新再做一遍,所以架构设计在游戏开发中是非常重要的,而且是必须要掌握的技术。下面重点给读者介绍架构设计中的MVC和FSM架构模式,效果如下所示:


MVC架构模式在前面的优化系列中给读者提过,下面就详细的告诉读者如何编写代码?给读者详细的分析一下,拿窗口的切换进行距离,游戏运行时,首先是创立界面,我们把每个界面作为一个窗口,比如LoginWindow,HeroWindow等。它们也是作为View界面,这样游戏中就会出现很多界面的设计,效果如下所示:


下面分析界面的编写,上文提到的每个UI就是一个Window,也是一个View,这么多View肯定有自己的共性,我们可以将其定义为基类,基类称为BaseWindow,代码编写如下所示:

[csharp] view plain copy
 
  1. namespace Game.View  
  2. {  
  3.     public abstract class BaseWindow  
  4.     {  
  5.         protected Transform mRoot;  
  6.   
  7.         protected EScenesType mScenesType; //场景类型  
  8.         protected string mResName;         //资源名  
  9.         protected bool mResident;          //是否常驻   
  10.         protected bool mVisible = false;   //是否可见  
  11.         
  12.   
  13.         //类对象初始化  
  14.         public abstract void Init();  
  15.   
  16.         //类对象释放  
  17.         public abstract void Realse();  
  18.   
  19.         //窗口控制初始化  
  20.         protected abstract void InitWidget();  
  21.   
  22.         //窗口控件释放  
  23.         protected abstract void RealseWidget();  
  24.   
  25.         //游戏事件注册  
  26.         protected abstract void OnAddListener();  
  27.   
  28.         //游戏事件注消  
  29.         protected abstract void OnRemoveListener();  
  30.   
  31.         //显示初始化  
  32.         public abstract void OnEnable();  
  33.   
  34.         //隐藏处理  
  35.         public abstract void OnDisable();  
  36.   
  37.         //每帧更新  
  38.         public virtual void Update(float deltaTime) { }  
  39.   
  40.         //取得所以场景类型  
  41.         public EScenesType GetScenseType()  
  42.         {  
  43.             return mScenesType;  
  44.         }  
  45.   
  46.         //是否已打开  
  47.         public bool IsVisible() { return mVisible;  }  
  48.   
  49.         //是否常驻  
  50.         public bool IsResident() { return mResident; }  
  51.   
  52.         //显示  
  53.         public void Show()  
  54.         {  
  55.             if (mRoot == null)  
  56.             {  
  57.                 if (Create())  
  58.                 {  
  59.                     InitWidget();  
  60.                 }  
  61.             }  
  62.   
  63.             if (mRoot && mRoot.gameObject.activeSelf == false)  
  64.             {  
  65.                 mRoot.gameObject.SetActive(true);  
  66.   
  67.                 mVisible = true;  
  68.   
  69.                  OnEnable();  
  70.   
  71.                 OnAddListener();  
  72.             }  
  73.         }  
  74.   
  75.         //隐藏  
  76.         public void Hide()  
  77.         {  
  78.             if (mRoot && mRoot.gameObject.activeSelf == true)  
  79.             {  
  80.                 OnRemoveListener();  
  81.                 OnDisable();  
  82.   
  83.                 if (mResident)  
  84.                 {  
  85.                     mRoot.gameObject.SetActive(false);  
  86.                 }  
  87.                 else  
  88.                 {  
  89.                     RealseWidget();  
  90.                     Destroy();  
  91.                 }  
  92.             }  
  93.   
  94.             mVisible = false;  
  95.         }  
  96.   
  97.         //预加载  
  98.         public void PreLoad()  
  99.         {  
  100.             if (mRoot == null)  
  101.             {  
  102.                 if (Create())  
  103.                 {  
  104.                     InitWidget();  
  105.                 }  
  106.             }  
  107.         }  
  108.   
  109.         //延时删除  
  110.         public void DelayDestory()  
  111.         {  
  112.             if (mRoot)  
  113.             {  
  114.                 RealseWidget();  
  115.                 Destroy();  
  116.             }  
  117.         }  
  118.   
  119.         //创建窗体  
  120.         private bool Create()  
  121.         {  
  122.             if (mRoot)  
  123.             {  
  124.                 Debug.LogError("Window Create Error Exist!");  
  125.                 return false;  
  126.             }  
  127.   
  128.             if (mResName == null || mResName == "")  
  129.             {  
  130.                 Debug.LogError("Window Create Error ResName is empty!");  
  131.                 return false;  
  132.             }  
  133.   
  134.             if (GameMethod.GetUiCamera.transform== null)  
  135.             {  
  136.                 Debug.LogError("Window Create Error GetUiCamera is empty! WindowName = " + mResName);  
  137.                 return false;  
  138.             }  
  139.   
  140.             GameObject obj = LoadUiResource.LoadRes(GameMethod.GetUiCamera.transform, mResName);  
  141.   
  142.             if (obj == null)  
  143.             {  
  144.                 Debug.LogError("Window Create Error LoadRes WindowName = " + mResName);  
  145.                 return false;  
  146.             }  
  147.   
  148.             mRoot = obj.transform;  
  149.   
  150.             mRoot.gameObject.SetActive(false);  
  151.   
  152.             return true;  
  153.         }  
  154.   
  155.         //销毁窗体  
  156.         protected void Destroy()  
  157.         {  
  158.             if (mRoot)  
  159.             {  
  160.                 LoadUiResource.DestroyLoad(mRoot.gameObject);  
  161.                 mRoot = null;  
  162.             }  
  163.         }  
  164.   
  165.         //取得根节点  
  166.         public Transform GetRoot()  
  167.         {  
  168.             return mRoot;  
  169.         }  
  170.     }  
  171. }  
以上是关于窗体的基类,实现了所有窗体需要创建的方法,创建窗体,销毁窗体,预加载,掩藏 等操作。实行按的具体操作类需要继承该窗体类,比如LoginWindow的写法如下所示:

[csharp] view plain copy
 
  1. namespace Game.View  
  2. {  
  3.     public class LobbyWindow : BaseWindow  
  4.     {  
  5.         public LobbyWindow()  
  6.         {  
  7.             mScenesType = EScenesType.EST_Login; //场景类型  
  8.             mResName = GameConstDefine.LoadGameLobbyUI; //资源名字  
  9.             mResident = false;  //是否常驻内存  
  10.         }  
  11.   
  12.         ////////////////////////////继承接口/////////////////////////  
  13.         //类对象初始化  
  14.         public override void Init()  
  15.         {  
  16.             EventCenter.AddListener(EGameEvent.eGameEvent_LobbyEnter, Show);  
  17.             EventCenter.AddListener(EGameEvent.eGameEvent_LobbyExit, Hide);   
  18.         }  
  19.   
  20.         //类对象释放  
  21.         public override void Realse()  
  22.         {  
  23.             EventCenter.RemoveListener(EGameEvent.eGameEvent_LobbyEnter, Show);  
  24.             EventCenter.RemoveListener(EGameEvent.eGameEvent_LobbyExit, Hide);   
  25.         }  
  26.   
  27.         //窗口控件初始化  
  28.         protected override void InitWidget()  
  29.         {             
  30.             mHomepage = mRoot.FindChild("StartMenuManager/StartMenuBtn/Homepage").GetComponent();  
  31.             UIGuideCtrl.Instance.AddUiGuideEventBtn(mHomepage.gameObject);  
  32.             mBattle = mRoot.FindChild("StartMenuManager/StartMenuBtn/Battle").GetComponent();  
  33.             mMarket = mRoot.FindChild("StartMenuManager/StartMenuBtn/Market").GetComponent();  
  34.             mInteraction = mRoot.FindChild("StartMenuManager/StartMenuBtn/Interaction").GetComponent();  
  35.   
  36.             UIGuideCtrl.Instance.AddUiGuideEventBtn(mMarket.gameObject);  
  37.             mDiamondText = mRoot.FindChild("Status/Diamond/Label").GetComponent();  
  38.             mGoldText = mRoot.FindChild("Status/Gold/Label").GetComponent();  
  39.             mSettingBtn = mRoot.FindChild("Status/Setting").GetComponent();  
  40.   
  41.             UIGuideCtrl.Instance.AddUiGuideEventBtn(mBattle.gameObject);  
  42.             EventDelegate.Add(mHomepage.onChange, OnHomePageChange);  
  43.             EventDelegate.Add(mBattle.onChange, OnBattleChange);  
  44.             EventDelegate.Add(mMarket.onChange, OnMarketChange);  
  45.             EventDelegate.Add(mInteraction.onChange, OnInteractionChange);  
  46.             UIEventListener.Get(mHeadIcon.transform.parent.gameObject).onClick += InfoPersonPress;  
  47.         }  
  48.         private void InfoPersonPress(GameObject go)  
  49.         {  
  50.             GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_PersonalInfo);  
  51.   
  52.             LobbyCtrl.Instance.AskPersonInfo();  
  53.             //PresonInfoCtrl.Instance.Enter();  
  54.         }  
  55.         
  56.         //窗口控件释放  
  57.         protected override void RealseWidget()  
  58.         {  
  59.         }  
  60.   
  61.   
  62.         //游戏事件注册  
  63.         protected override void OnAddListener()  
  64.         {  
  65.             EventCenter.AddListener(EGameEvent.eGameEent_ChangeMoney, RefreshMoney);  
  66.             EventCenter.AddListener<bool>(EGameEvent.eGameEvent_ReceiveLobbyMsg, NewChat);  
  67.             EventCenter.AddListener(EGameEvent.eGameEvent_AddNewMailReq, NoticeNewMail);  
  68.             EventCenter.AddListener(EGameEvent.eGameEvent_ChangeNickName,ChangeNickName);  
  69.             EventCenter.AddListener(EGameEvent.eGameEvent_ChangeHeadID, ChangeHeadID);  
  70.   
  71.             EventCenter.AddListener(EGameEvent.eGameEvent_ChangeUserLevel, ChangeLevel);  
  72.         }  
  73.         private void ChangeHeadID()  
  74.         {  
  75.             mHeadIcon.spriteName = GameUserModel.Instance.GameUserHead.ToString();  
  76.         }  
  77.   
  78.         //游戏事件注消  
  79.         protected override void OnRemoveListener()  
  80.         {  
  81.             EventCenter.RemoveListener(EGameEvent.eGameEent_ChangeMoney, RefreshMoney);  
  82.             EventCenter.RemoveListener<bool>(EGameEvent.eGameEvent_ReceiveLobbyMsg, NewChat);  
  83.             EventCenter.RemoveListener(EGameEvent.eGameEvent_AddNewMailReq, NoticeNewMail);  
  84.             EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeNickName, ChangeNickName);  
  85.             EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeHeadID, ChangeHeadID);  
  86.             EventCenter.RemoveListener(EGameEvent.eGameEvent_ChangeUserLevel, ChangeLevel);  
  87.         }  
  88.   
  89.         //显示  
  90.         public override void OnEnable()  
  91.         {  
  92.   
  93.         }  
  94.   
  95.         //隐藏  
  96.         public override void OnDisable()  
  97.         {  
  98.   
  99.         }  
  100.   
  101.         public void ChangeUserLevel()  
  102.         {  
  103.             mLevel.text = GameUserModel.Instance.UserLevel.ToString();  
  104.         }  
  105. ="white-space:pre">  //回调事件  
  106.         public void OnHomePageChange()  
  107.         {  
  108.             //todo  
  109.             mLevel.text = GameUserModel.Instance.UserLevel.ToString();  
  110.             mNickName.text = GameUserModel.Instance.GameUserNick;  
  111.             mHeadIcon.spriteName = GameUserModel.Instance.GameUserHead.ToString();  
  112.             mGold.text = GameUserModel.Instance.mGameUserGold.ToString();  
  113.             mDiamond.text = GameUserModel.Instance.mGameUserDmd.ToString();  
  114.             VipSignLevel.text = "VIP "+GameUserModel.Instance.GameUserVipLevel.ToString();  
  115.             int level = GameUserModel.Instance.UserLevel;  
  116.             mLevel.text = level.ToString();  
  117.               
  118.             LevelConfigInfo leveinfo = ConfigReader.GetLevelInfo(level);  
  119.             if (leveinfo != null)  
  120.             {  
  121.                 mExp.text = GameUserModel.Instance.GameUserExp + "/" + leveinfo.LevelUpExp;  
  122.                 mExp.transform.parent.GetComponent().fillAmount = GameUserModel.Instance.GameUserExp / leveinfo.LevelUpExp;  
  123.                 if (level >= 29 && GameUserModel.Instance.GameUserExp >= leveinfo.LevelUpExp)  
  124.                 {  
  125.                     level = 30;  
  126.                     mLevel.text = level.ToString();  
  127.                     mExp.gameObject.SetActive(false);  
  128.                     mExp.transform.parent.GetComponent().fillAmount = 1f;  
  129.                 }  
  130.             }  
  131.               
  132.             if (mHomepage.value)  
  133.             {  
  134.                 GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_HomePage);  
  135.                 HomePageCtrl.Instance.Enter();  
  136.             }  
  137.             else  
  138.             {  
  139.                 HomePageCtrl.Instance.Exit();  
  140.             }  
  141.         }  
  142.   
  143.         public void OnBattleChange()  
  144.         {  
  145.             if (mBattle.value)  
  146.             {  
  147.                 GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Battle);  
  148.                 BattleCtrl.Instance.Enter();  
  149.             }  
  150.             else  
  151.             {  
  152.                 BattleCtrl.Instance.Exit();  
  153.             }  
  154.         }  
  155.   
  156.         public void OnMarketChange()  
  157.         {  
  158.             if (mMarket.value)  
  159.             {  
  160.                 GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Market);  
  161.                 MarketCtrl.Instance.Enter();  
  162.             }  
  163.             else  
  164.             {  
  165.                 MarketCtrl.Instance.Exit();  
  166.             }  
  167.         }  
  168.   
  169.         public void OnInteractionChange()  
  170.         {  
  171.             if (mInteraction.value)  
  172.             {  
  173.                 GameLog.Instance.AddUIEvent(GameLog.UIEventType.UIEventType_Friend);  
  174.                 SocialCtrl.Instance.Enter();  
  175.             }  
  176.             else  
  177.             {  
  178.                 SocialCtrl.Instance.Exit();  
  179.             }  
  180.         }  
  181.   
  182.         public void MailListBtn(GameObject obj)  
  183.         {  
  184.             mMailBtnBg.SetActive(false);  
  185.   
  186.             MailCtrl.Instance.Enter();  
  187.         }  
  188.     }  
  189.   
  190.   
  191. }  
该类主要是实现整个UI的逻辑编写,其他的窗口编写类似。下面编写Control控制类代码的编写,示例代码如下:

[csharp] view plain copy
 
  1.  public class LoginCtrl : Singleton  
  2.  {  
  3.      public void Enter()  
  4.      {  
  5.          EventCenter.Broadcast(EGameEvent.eGameEvent_LoginEnter);  
  6.      }  
  7.   
  8.      public void Exit()  
  9.      {  
  10.          EventCenter.Broadcast(EGameEvent.eGameEvent_LoginExit);  
  11.      }  
  12.   
  13.      //登陆  
  14.      public void Login(string account, string pass)  
  15.      {  
  16.   
  17.      }  
  18.   
  19.      //登陆错误反馈  
  20.      public void LoginError(int code)  
  21.      {  
  22.   
  23.      }  
  24.   
  25.      //接收GateServer信息  
  26.      public void RecvGateServerInfo(Stream stream)  
  27.      {  
  28.   
  29.      }  
  30.   
  31.      //登陆失败  
  32.      public void LoginFail()  
  33.      {  
  34.   
  35.      }  
  36.   
  37.      //选择LoginServer  
  38.      public void SelectLoginServer(int i)  
  39.      {  
  40.   
  41.      }  
  42.      //开始游戏  
  43.      public void GamePlay()  
  44.      {  
  45.   
  46.      }  
  47. }  
[csharp] view plain copy
 
  1. }  
控制类的主要作用是进行一些消息的传递,这也是为了解除模块之间的耦合性,该模块的主要核心是Enter函数和Exit函数。后面继续代码的编写。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论