Unity3D优化技巧系列五

原创 2017年04月02日 18:06:16

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

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


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


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

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;
        }
    }
}

以上是关于窗体的基类,实现了所有窗体需要创建的方法,创建窗体,销毁窗体,预加载,掩藏 等操作。实行按的具体操作类需要继承该窗体类,比如LoginWindow的写法如下所示:

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();
        }
    }


}
该类主要是实现整个UI的逻辑编写,其他的窗口编写类似。下面编写Control控制类代码的编写,示例代码如下:

    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函数。后面继续代码的编写。。。。


版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

cocos2dx-3.x:骨骼动画描边(spine)

在网上查了很久,一直都没有找到骨骼动画描边的方法,cocos自身带的shader中有个给Sprite描边的方法,看了很久,都没有用上,内心甚是纠结,最后查了好久源码,发现spine中有个方法“setS...

Unity3D教你制作Bezier和Spine曲线编辑器三

继续接着介绍曲线编辑器的制作,上篇博客介绍了关于Bezier曲线的制作,接下来给读者介绍Spine B样条曲线之作。 如果要创建复杂的曲线,我们需要连接多个曲线,这样的构造称为样条。让我们通过复制Be...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

Unity2d游戏开发:UGUI 与 Spine 的完美结合

孙广东   2016.3.18将 spine 动画 转化为 Ugui 系统的 Graphics 元素:(Unity 5.3以上)SkeletonGraphic.cs       代替官方的  Skel...

Unity3D优化技巧系列八

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》...
  • jxw167
  • jxw167
  • 2017-04-04 12:49
  • 2173

Unity3D优化技巧系列七

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》...
  • jxw167
  • jxw167
  • 2017-04-03 20:45
  • 2022

MMORPG游戏服务器技术选型参考

游戏服务器一般追求稳定和效率,所以偏向于保守,使用的技术手段也是以已经过验证、开发人员最熟悉、能HOLD为主要前提。 1、典型按场景分服设计   开发语言: c++   数据库:mysql   架构:...

大型多人在线游戏服务器架构设计

由于大型多人在线游戏服务器理论上需要支持无限多的玩家,所以对服务器端是一个非常大的考验。服务器必须是安全的,可维护性高的,可伸缩性高的,可负载均衡的,支持高并发请求的。面对这些需求,我们在设计服务器的...

碉堡了!程序员用深度学习写了个老板探测器(附源码)

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》...
  • jxw167
  • jxw167
  • 2017-01-12 10:25
  • 5705

Cocos2d-x 3.x 图形学渲染系列七

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人; 已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社 和《Unity3D实战核心...
  • jxw167
  • jxw167
  • 2017-01-07 13:44
  • 4229

cocos2d里的法线贴图

法线贴图: 可以看到法线贴图整体一般都是偏向蓝色调,这是因为做贴图的时候法线一般朝向z轴就是vec3(0,0,1),  大象的头顶和脊梁都朝向y轴就是vec3(0,1,0)所以偏蓝,大腿...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)