首页 > 代码库 > CocosStdio 项目孵化记-动作卡牌游戏-系统设计-UI系统
CocosStdio 项目孵化记-动作卡牌游戏-系统设计-UI系统
根据解决方案,我们的UI是用Cocostdio的UI编辑器做的,在通过UI编辑器导出的资源是(.json文件 + 碎图)。
这样,会出来一个JSON文件 ,例如A.json,然后一堆碎图。为什么不使用大图呢!因为,我们打算Texturepacker对碎图进行打包,来做资源优化。
这样拼接界面的事,就可以有策划或者美术或者其他人做了。程序可以安心的写代码了,只需要做某些特殊功能的时候,让拼界面的人员给制定的控件做好命名。然后程序根据这些命名写程序就OK了。
其实我们更关注的是如何把这些界面有规律的调度起来。
在软件开发中,要注意一个问题叫MVC,Model-View-Control 其实我们所有的架构都是基于这个起来的。做GUI的架构我们必须做到下面几点。
1.UI资源的载入和释放
2.UI界面和逻辑功能分开。其实就是一遍进行资源的制作,一遍程序写功能。然后通过中间一层代码,将有关系的两者联系到一起。做到代码和逻辑的分离。
3.UI的调度问题,在上一篇文章中已经提及到了。
好 ,就以上3个问题,我们展开设计。按照一般的设计思路,我们首先做了一个单例类 CGuiMgr
不懂单例的同学,可以去查一下设计模式---单例是什么?
class CGuiMgr{protected: CGuiMgr(); ~CGuiMgr(); static CGuiMgr m_Inst;public: static CGuiMgr* GetInst(); void init(); CGuiUnit* CreateGui(const char* _name); CGuiUnit* GetGui(const char* _name,bool _create = true); void DelGui(const char* _name); void RegisterGui(CGuiUnit* _gui); void update(float _fTime);protected: typedef std::map<string, CGuiUnit*> GUIPOOL; GUIPOOL m_GuiPool; typedef std::map<string, string> GUIRESTABLE; GUIRESTABLE m_GuiResTable;};
通过单例类CGuiMgr 来控制它的基本元素CGuiUnit ( 下面只是部分代码 只拾取了关键部分)
//每个GUI 封装一个GUI节点 用于对应资源文件 class CGuiUnit :public TouchGroup //TouchGroup 继承了CCLayer,它可以接受消息的哦,{ friend class CGuiMgr;protected: CGuiUnit(const char* _name,const char* _resname); ~CGuiUnit();public: static CGuiUnit* CreateInLua(const char* _name,const char* _resname); virtual void onEnter(); virtual void onExit(); virtual bool Load(); virtual bool UnLoad(); void setResFile(const char* _file); const char* getName(); void select_callback(unsigned int _colorID); //精确拾取 virtual void AdapteScreen(); //屏幕适配 void run(float fTime);protected: void _bind(); void _unbind(); bool isLoad; string m_Name; //配表配置的名称,也是唯一一个名称,相当于Key 这个相当重要了,所有的关联真的都要靠key的 string m_ResFileName; //资源文件名称 Layout* m_pLayerout; //对应从Res文件中导出的节点 bool m_bAdapted; CGuiActionQueue* m_pActQue; //顺序动画,这个很重要哦};
我们只需要从中关注的一个问题,就是CGuiMgr 去管理CGuiUnit。然后每一个CGuiUnit对应一个编辑器导出的文件。当然我们会给每一个界面起一个名称(字符串)。当然,这些关系都会写到配表当中,由策划来填写。
注意:
在CGuiMgr上有一个函数叫做 void RegisterGui(CGuiUnit* _gui); 这个函数辅助将GuiUnit的基本元素注册到管理类中。
CGuiUnit::CGuiUnit(const char* _name,const char* _resname):isLoad(false),m_Name(_name),m_pLayerout(NULL),m_ResFileName(_resname),m_bAdapted(false),m_pActQue(NULL){ m_pActQue = new CGuiActionQueue; init(); CGuiMgr::GetInst()->RegisterGui(this);}
也就是CGuiUnit在构造的过程中,会自动注册。这样每一个CGuiUnit对象都不会丢失的。
//CGuiMgr CGuiMgr::m_Inst;CGuiMgr* CGuiMgr::GetInst(){ return &m_Inst;}CGuiMgr::CGuiMgr(){}CGuiMgr::~CGuiMgr(){}void CGuiMgr::init() //解析配表{ typedef map<int,TD_UIRes*> UIRESPool; UIRESPool::iterator it = CCltBaseDataTbl::Inst()->m_mapUIRes.begin(); while( it!=CCltBaseDataTbl::Inst()->m_mapUIRes.end() ) { TD_UIRes* t_uires_data = http://www.mamicode.com/it->second; if(t_uires_data) { string tmp_name = t_uires_data->uiname(); string tmp_value = http://www.mamicode.com/t_uires_data->resname(); m_GuiResTable[tmp_name] = tmp_value; } it++; } CREATE_GUI(CGuiJingQian); //这个宏有点意思 。。。。。。。。 CREATE_GUI(CGuiErrorMessage);}CGuiUnit* CGuiMgr::CreateGui(const char* _name){ return GetGui(_name,true);}CGuiUnit* CGuiMgr::GetGui(const char* _name,bool _create) //保证给你一个UI对象,但是_create 设置成true{ GUIPOOL::iterator it = m_GuiPool.find(_name); if(it!=m_GuiPool.end()) return it->second; if(_create) { GUIRESTABLE::iterator it_res = m_GuiResTable.find(_name); if( it_res!=m_GuiResTable.end() ) { CGuiUnit* gui = new CGuiUnit(_name,it_res->second.c_str()); gui->Load(); return gui; } } return NULL;}void CGuiMgr::RegisterGui(CGuiUnit* _gui) //注册回来,用于管理{ if(_gui) m_GuiPool[_gui->getName()] = _gui;}void CGuiMgr::DelGui(const char* _name){ GUIPOOL::iterator it = m_GuiPool.find(_name); if(it!=m_GuiPool.end()) { if (it->second != NULL) it->second->release(); m_GuiPool.erase(it); }}void CGuiMgr::update(float _fTime) //所有UI都给你一个更新的机会,用不用就看你自己的了{ GUIPOOL::iterator iter = m_GuiPool.begin(); for (;iter != m_GuiPool.end();++iter) { if (iter->second == NULL) continue; iter->second->run(_fTime); }}
管理类CGuiMgr重要的实现:
init() 初始化函数,主要是解析配表,将资源的对应关系解析出来。并存在当管理类当中的Map数据结构中。
CreateGui() 和GetGui() 其实就是来创建一个CGuiUnit的基本对象的,其中GetGui()函数当中有一个参数 叫_create,它的意思就是,通过这个借口是否一定会拿到一个对象。如果是真,表示我一定要获得我想要的CGuiUnit对象,如果内存当中没有此对象,则创建一个新的。
其实我们在写的时候,这个都会设置成True,如果在一些判断语句,就要设置成False了。这样,我们就保证了,在内存中同一个名称的GuiUnit对象只有一个,也就一个UI只有一个对象,剩下的就是UI切换的关系了。
我们还是看看那个宏吧!!!
下面的博客 我给它取个名称 叫做 项目孵化记录 哈哈 有点意思吧!
CocosStdio 项目孵化记-动作卡牌游戏-系统设计-UI系统