`cocos2dx 非完整` UI解析模块

昨天在cocos2dx的一个群里,遇到一位匿名为x的朋友询问的问题,是关于ui的.他使用c++写了不少的ui封装节点,用来实现游戏中的各种不同效果.然后现在想改用lua,于是尝试使用最小代价去复用自己的代码.当然这个是可以做到的,相信很多人都是知道方法的.今天的这篇文章就来谈谈ui部分的处理以及个人的见解.

我们都知道,cocos2dx引擎提供了ui工具cocostudio.后来改名为cocos engine.这些就不赘述了,很多人都会使用这款工具.新版本的工具我没有使用过,不过我承认是方便了很多.可是很多时候我们期望有着自己一套的资源管理方式,尤其是项目琐碎ui资源,效果资源等等一大堆的时候,后期优化app包大小的时候也是个问题. 所以我个人倾向的方案是提供基于项目的ui库.当然对于lua这样的语言不存在库的说法,我在fw目录下面提供了一个ui模块,为了解决自己提供的ui方式,首先得想明白我们如何去使用自己的ui模块.我期望的方式是这个样子的:

 1 local component_cfg =
 2 {
 3     {
 4         name     = "bg_img",
 5         creator = ui_parser.parsers.img,  -- 基于cocos2dx ui
 6         pos     = cc.p(100,200),
 7         -- ...
 8         parent  = self,
 9     },
10     {
11         name    = "loading_bar",
12         creator = ui_parser.parsers.widget_loading_bar, -- 基于自己扩展的ui
13         -- ...
14         parent  = "bg_img",        -- 节点内部相互添加也可以支持
15     },
16
17     onfinsh = function(components)
18         components["loading_bar"]:set_percent(100), -- 初始化以后的操作
19     end,
20 }
21
22 local components = ui_parser.parse(component_cfg)

看上面我提供的实例代码,我期望的是创建一个ui模块,只需要按照lua table的方式一样配置就好.这样有一个好处,可以复用很多其他模块的代码.需要的其他功能我都在注释中写出来了.接下来继续分析一下需求,我们可能会有自己的ui封装,所以得提供一个基类,当然这是仿照oop的说法,所以我就提供了一个ui_widget文件用来实现这个功能:

 1 --小岩<[email protected]>
 2 --2015-5-30 13:25
 3 local ui_widget = {}
 4
 5 function ui_widget:ctor(cfg)
 6     self.type_ = "ui_widget"
 7     self.cfg_  = cfg
 8     self:init_widget()
 9 end
10
11 function ui_widget:init_widget()
12     error(self.__cname .. ":init_widget() method not implemented!")
13 end
14
15 function ui_widget:get_root_node()
16     error(self.__cname .. ":get_root_node() method not implemented!")
17 end
18
19 function ui_widget:add_to_node(parent)
20     if parent.type_ and parent.type_ == "ui_widget" then
21         parent:get_root_node():addChild(self:get_root_node())
22     else
23         parent:addChild(self:get_root_node())
24     end
25 end
26
27 function ui_widget:add_child(child)
28     if child.type_ and child.type_ = "ui_widget" then
29         self:get_root_node():addChild(child:get_root_node())
30     else
31         self:get_root_node():addChild(child)
32     end
33 end
34
35 function ui_widget:set_ap(ap)
36     self:get_root_node():setAnchorPoint(ap)
37 end
38
39 function ui_widget:get_ap()
40     return self:get_root_node():getAnchorPoint()
41 end
42
43 function ui_widget:set_pos(pos)
44     self:get_root_node():setPosition(pos)
45 end
46
47 function ui_widget:get_pos()
48     local posx, posy = self:get_root_node():getPosition()
49     return cc.p(posx, posy)
50 end
51
52 return ui_widget

好了,基本的东西已经提供好了,下面就去处理.首先是处理creator,因为需求中明确的表示,第一我们要兼容cocos ui创建的api,另外我们还会有自己的ui封装.所以我将这些节点的创建方式都放在一起,方便管理.所以就有了ui_creator文件:

 1 --小岩<[email protected]>
 2 --2015-5-30 12:45
 3 local ui_creator = {}
 4
 5 ui_creator.creators_ =
 6 {
 7     ccsprite =
 8     {
 9         function(...)
10             return cc.Sprite:create(...)
11         end,
12         function(...)
13             return cc.Sprite:createWithSpriteFrameName(...)
14         end
15     },
16 }
17
18 function ui_creator.new_ccsprite(mode, ...)
19     return ui_creator.creators_.ccsprite[mode](...)
20 end
21
22 return ui_creator

可能很多人会奇怪这里面的mode参数是做什么用的,这个是用作资源管理用的,在开发初期的时候我们不会对资源进行合并处理,大部分都是散乱的放在各个文件夹中,而后期的时候我们会对资源进行合并.例如打包成为png大图等.通过浏览cocos2dx源码可以知道,cocos2dx的资源管理方式分为local和cache,所以我就提供了两种不同的创建接口.但是又消除了api的不同,对于使用者而言,仅仅是指定一下mode参数而已.对于api消除不同性接下来还要说.看ui_widget可以知道我提供的api和cocos2dx提供的api不同.所以我要消除这部分的不同性.不过要先来看一下ui_parser的实现:

 1 --小岩<[email protected]>
 2 --2015-5-30 12:45
 3 local ui_creator = require "fw.ui.ui_creator"
 4 local checker    = require "fw.ui.check"
 5 local api_adapter= require "fw.ui.api_adapter"
 6
 7 local ui_parser = {}
 8
 9 -- 解析ui控件函数
10 ui_parser.parsers =
11 {
12     img = function(cfg)
13         checker(cfg.mode, "number", string.format("ui_parser.parsers_.img() -- wrong mode %d", tonumber(cfg.mode)))
14         checker(cfg.img,  "string", string.format("ui_parser.parsers_.img() -- wrong img %s",  tostring(cfg.img)))
15         local img_ins = ui_creator.new_ccsprite(cfg.mode, cfg.img)
16         api_adapter.adapter_cc(img_ins)
17         return img_ins
18     end,
19 }
20
21 local function _strict_loop_with_given_list(list, callback)
22     for index, item in ipairs(list) do
23         callback(index, item)
24     end
25 end
26
27 --解析ui,生成ui控件
28 function ui_parser.parse(component_cfg)
29     local ui_components_ = {}
30     local ui_cbs_          = {}
31     local unspports_     = {}
32
33     --解析callback
34     local function parse_cb(ui_cb)
35         table.insert(ui_cbs_, ui_cb)
36     end
37
38     --解析ui控件
39     local function parse_ui(ui_cfg)
40         checker(ui_cfg.name,     "string",     string.format("ui_parser.parse.parse_ui() -- cfg name error!"))
41         checker(ui_cfg.creator, "function", string.format("ui_parser.parse.parse_ui() -- cfg creator error!"))
42
43         --处理节点相互添加
44         if ui_cfg.parent and type(ui_cfg.parent) == "string" then
45             parse_cb(function(ui_components)
46                     local ui_component                 = ui_components[ui_cfg.name]
47                     local ui_component_type         = ui_component.type_
48                     local ui_component_parent         = ui_componens[ui_cfg.parent]
49                     local ui_component_parent_type     = ui_component_parent.type_
50                     if ui_component_type and ui_component_type == "ui_widget" then
51                         ui_component:add_to_node(ui_component_parent)
52                     else
53                         if ui_component_parent_type and ui_component_parent_type == "ui_widget" then
54                             ui_component_parent:add_child(ui_component)
55                         end
56                     end
57                 end)
58         end
59
60         ui_components_[ui_cfg.name] = ui_cfg.creator(ui_cfg)
61     end
62
63     --保存unspport
64     local function parse_unspports(unspport)
65         table.insert(unspports_, unspport)
66     end
67
68     _strict_loop_with_given_list(component_cfg, function(_, item)
69             local item_type = type(item)
70             if item_type == "table" then
71                 parse_ui(item)
72             elseif item_type == "function" then
73                 parse_cb(item)
74             else
75                 parse_unspports(item)
76             end
77         end)
78
79     _strict_loop_with_given_list(ui_cbs_, function(_, cb)
80             cb(ui_components_)
81         end)
82
83     ui_components_["unspport"] = unspports_
84
85     return ui_components_
86 end
87
88
89 return ui_parser

其中我做了很多的事情,例如很多时候我们在做UI布局的时候需要做相对适配,所以坐标不好指定,所以我在解析compoennt_cfg的时候认为如果提供的节点是function类型的话,那么就等所有的节点都解析完了之后统一操作,这样就可以处理相对布局的东西了.另外cocos2dx node派生的节点,和我们事先的ui_widget派生的节点如何相互添加的操作也做了.好了,创建的节点我在ui_parser.parsers中封装了,下面我们就来处理api的不同性,并消除掉。

 1 --小岩<[email protected]>
 2 --2015-5-30 14:17
 3 local api_adapter = {}
 4
 5 api_adapter.cc =
 6 {
 7     parent = function(node, parent)
 8                 if type(parent) ~= "string" then
 9                     if parent.type_ and parent.type_ == "ui_widget" then
10                         parent:add_child(node)
11                     else
12                         parent:addChild(node)
13                     end
14                 end
15             end,
16     pos   = function(node, pos)
17                 node:setPosition(pos)
18             end,
19     ap    = function(node, ap)
20                 node:setAnchorPoint(ap)
21             end,
22     show  = function(node, show)
23                 node:setVisible(show)
24             end,
25     content_size = function(node,  content_size)
26                 node:setContentSize(content_size)
27             end,
28     rotation = function(node, rotation)
29                 node:setRotation(rotation)
30             end,
31     scale = function(node, scale)
32                 node:setScale(scale)
33             end,
34
35     scalex = function(node, scalex)
36                 node:setScaleX(scalex)
37             end,
38     scaley = function(node, scaley)
39                 node:setScaleY(scaley)
40             end,
41     rsx    = function(node, rsx)
42                 node:setRotationSkewX(rsx)
43             end,
44     rsy    = function(node, rsy)
45                 node:setRotationSkewY(rsy)
46             end,
47 }
48
49 api_adapter.widget =
50 {
51     parent = function(node, parent)
52                 if type(parent) ~= "string" then
53                         node:add_to_parent(parent)
54                 end
55             end,
56     pos    = function(node, pos)
57                 node:set_pos(pos)
58             end,
59     ap     = function(node, ap)
60                 node:set_ap(ap)
61             end,
62     show   = function(node, show)
63                 node:get_root_node():setVisible(show)
64             end,
65     content_size = function(node, content_size)
66                 node:set_content_size(content_size)
67             end,
68 }
69
70 function api_adapter.adapter_cc(node, cfg)
71     if cfg.parent then api_adapter.cc.parent(node, cfg.parent) end
72     if cfg.pos    then api_adapter.cc.pos(node, cfg.pos) end
73     if cfg.ap     then api_adapter.cc.ap(node, cfg.ap) end
74     if cfg.show or type(cfg.show) == "boolean" then api_adapter.cc.show(node, cfg.show) end
75     if cfg.content_size then api_adapter.cc.content_size(node, cfg.content_size) end
76     if cfg.rotation then api_adapter.cc.rotation(node, cfg.rotation) end
77     if cfg.scale  then api_adapter.cc.scale(node, cfg.scale) end
78     if cfg.scalex then api_adapter.cc.scalex(node, cfg.scalex) end
79     if cfg.scaley then api_adapter.cc.scaley(node, cfg.scaley) end
80     if cfg.rsx    then api_adapter.cc.rsx(node, cfg.rsx) end
81     if cfg.rsy    then api_adapter.cc.rsy(node, cfg.rsy) end
82 end
83
84 function api_adapter.adapter_widget(node, cfg)
85     if cfg.parent then api_adapter.widget.parent(node, cfg.parent) end
86     if cfg.pos    then api_adapter.widget.pos(node, cfg.pos) end
87     if cfg.ap     then api_adapter.widget.ap(node, cfg.ap) end
88     if cfg.show   then api_adapter.widget.show(node, cfg.show) end
89     if cfg.content_size then api_adapter.widget.content_size(node, cfg.content_size) end
90 end
91
92 return api_adapter

我按部就班的提供了上面的工具. 这样就消除了api不同性. 如果添加了我们自己的ui封装,响应的在creator中添加创建函数,在parser中添加响应的解析,在api_adaper中添加相应的函数.这样就做到了我前面预期的事情了。

在这里要说一句抱歉,因为我并没有添加测试用例的功能,所以不能给大家提供直观的测试表现,很快我就会考虑添加的.这篇文章就到这里啦.希望对大家有用。

时间: 2024-10-11 08:02:13

`cocos2dx 非完整` UI解析模块的相关文章

`cocos2dx非完整` 日志模块 增量更新

在上一篇文章中,说到了"流程"的由来,以及我对流程的使用. 这一片就是对流程的应用.前一篇文章中说到了三条流程 check_log_measure, check_env_measure, check_update_measure.先来看看chenck_log_measure的源码: 1 --小岩<[email protected]> 2 --2015-5-28 1:29 3 local clm = class("check_log_measure", f

`cocos2dx非完整` 开始自己的FW模块

上一篇的文章中说到了一些个人习惯的东西以及一些简单的项目配置,这一篇文章我们来进一步完善一些东西.首先,打开编译以后的客户端执行,会看到一大堆的fileutils加载luac文件的提示,在终端显示一大堆,挺烦人的,我做的第一件事就是去修改他.这个很简单,有两种做法,第一种是在c++部分添加调用 1 cocos2d::FileUtils::getInstance()->setPopupNotify(false); 当然也可以在lua部分添加, 1 cc.FileUtils:getInstance(

`cocos2dx非完整` 添加xxtea加密模块

在上一篇文章中,我已经开始着手写自己的模块,也就是fw部分.其中上一篇文章中完成的是lua部分的配置解析部分,涉及一点点平台方面的封装.这一片文章我来说明一下我是如何处理cocos2dx资源加密的.首先需要说明白的是,资源是什么?资源分为哪几类? 在选择使用lua脚本开发后,包括lua文件,游戏美术资源,游戏的配置,我都统称为游戏资源,所以我期望的加密是能够加密所有这些东西.quick提供了xxtea,而cocos2dx也在luastack中整合了xxtea,我稍微做了一些修改.主要的修改思路是

`cocos2dx非完整` 游戏架构缩影 添加启动流程

这期的话题可能不是很好, 我没有想到很好的词句去更好的表达. 我一直都是很固执的认为, 同一类型的游戏,在开发做的前期工作上面其实都是可以复用的,也就是大同小异的.从游戏启动,启动日志,启动检查,检查更新,到进入游戏.这些都是那一套东西,我想把这些东西抽象一下,概括出一个叫做"流程"的概念. 我的想法就是流程是顺序执行的, 就像我喜欢画图,先做什么,然后做什么,做完什么做什么.其实从一款app启动到进入游戏,这之间的过程都是流程化进行的.还有一个很经典的例子,新手引导,其实新手引导就是

`fw服务端非完整` 工程开发初期的工作

前面写到了一些关于cocos2dx在开发中的一些模块以及一些解决方法,那些都属于本人的个人简介和个人倾向的解决方案.最近这几天我完善了一下ui解析的部分,当然也只是抽出一点点时间去做的这件事情.我添加了一个测试模块,保证了前面编码的各个模块都通过,android上面也是测试通过的,这个大家可以放心.现在我要暂时搁置一下cocos2dx系列部分,着手解决服务端部分. 在之前,我想先说一下我写fw服务端的出发点,简单,够用.先解释一下这里,所谓简单,够用.就是能够满足对接前面写到的cocos2dx部

浩哥解析MyBatis源码(十一)——Parsing解析模块之通用标记解析器(GenericTokenParser)与标记处理器(TokenHandler)

原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6724223.html 1.回顾 上面的几篇解析了类型模块,在MyBatis中类型模块包含的就是Java类型与Jdbc类型,和其间的转换处理.类型模块在整个MyBatis功能架构中属于基础组件之一,是提前注册到注册器中,并配置到Configuration中备用. 从这一篇开始解析Parsing解析模块,这个模块不同于Type模块,这个模块更像是一套工具模块.本篇先解析通用标记解析器Gene

cocos2dx 读取json及解析

ball.json 数据例如以下: { "entities": [ { "entity": { "TapOpposite": 0, "Interval": 0.95, "BallNum": 1 } }, { "entity": { "TapOpposite": 0, "Interval": 0.91, "BallNum": 2

[爬虫学习笔记]C#基于ARSoft.Tools.Net的DNS解析模块(半成品)

      最近在做爬虫的作业,今天学习的内容是关于DNS解析模块的制作的.使用的库为ARSoft.Tools.Net,它是一个非常强大的开源DNS控件库,包含.Net SPF validation, SenderID validation以及DNS Client.DNS Server接口.使用该接口可轻松实现DNS客户请求端及服务器解析端.项目地址:http://arsofttoolsnet.codeplex.com/,Nuget包地址:https://www.nuget.org/packag

cocos2dx 3.0 ui

这是这一张我觉得可以图,大概以后可以用到. cocos2dx 3.0 ui,布布扣,bubuko.com