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

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

1 cocos2d::FileUtils::getInstance()->setPopupNotify(false);

当然也可以在lua部分添加,

1 cc.FileUtils:getInstance():setPopupNotify(false)

两种做法都很简单,根据自己选择.我选择是在AppDelegate.cpp中添加.暂时没有在c++部分添加自己的模块,因为现在还不需要,后面需要的时候会再说.我将新项目中的其他lua文件全部删除了,res下面的所有资源也都删除了,修改了main.lua中的源码,只留下了引擎启动初始化glview部分的代码,这样就足够了,无论是开发一款什么样子的项目,我们都是从这里开始的.修改后的源码如下,很多同学不用看,只是为了保持我写文章的原始目的,尽量说明我的思路.

 1 -- 小岩<757011285@qq.com>
 2 -- 2015-5-25 13:10
 3 cc.FileUtils:getInstance():addSearchPath("res")
 4 cc.FileUtils:getInstance():addSearchPath("src")
 5
 6 require "cocos.init"
 7 local fw = require "fw.init"
 8
 9 function __G__TRACKBACK__(msg)
10     print("lua error: " .. tostring(msg) .. "\n")
11     print(debug.traceback())
12     return msg
13 end
14
15 local function main()
16     collectgarbage("collect")
17     -- avoid memory leak
18     collectgarbage("setpause", 100)
19     collectgarbage("setstepmul", 5000)
20
21     -- initialize director
22     local director = cc.Director:getInstance()
23     local glview = director:getOpenGLView()
24     if nil == glview then
25         glview = cc.GLViewImpl:createWithRect("HelloLua", cc.rect(0,0,900,640))
26         director:setOpenGLView(glview)
27     end
28
29     glview:setDesignResolutionSize(480, 320, cc.ResolutionPolicy.NO_BORDER)
30
31     --turn on display FPS
32     director:setDisplayStats(true)
33
34     --set FPS. the default value is 1.0/60 if you don‘t call this
35     director:setAnimationInterval(1.0 / 60)
36
37 end
38
39 local status, msg = xpcall(main, __G__TRACKBACK__)
40 if not status then
41     error(msg)
42 end

main.lua

好的,可能很多人做到这里,就会思考并开始写代码了.我像这样应该还是缺少很多东西的,尤其是我们做过一些项目后就知道,有很多基础的模块和功能还是需要的,实现这个过程就像是盖房子打地基,我就花费了半天的时间来做这件事情.我先是构思了一下,然后稍作修改了一下项目的目录结构.修改后的目录结构如下:

-- res

-- src

-- cocos

-- fw

-- ini.lua

-- util

-- fileutil.lua

-- platform.lua

-- convert.lua

-- oop

-- ini.lua

-- csv.lua

-- kv.lua

-- classickv.lua

-- game

-- main.lua

好的下面我来解释一下这个目录.我添加了fw目录作为项目通用的模块,这样做是有好处的,如果以后项目需要的话,做的好,我完全可以直接把这个模块拿过去,稍作修改甚至是不用修改就可以胜任了,也就是积累我们自己的代码.当然,鱿鱼经验受限,我们会一次又一次的重构这个模块,就像我,不停的去修改去完善,让它在某些方面更合理.其实昨天我主要是添加了三个方面的功能:

1.我将cc.FileUtils里面的结构全部倒入了我写的fileutil中,并添加了部分自己的功能,源码如下:

 1 -- 小岩<[email protected]>
 2 -- 2015-5-25
 3 local platform = require "fw.util.platform"
 4
 5 local fu = {}
 6 local cc_fileutils_ = cc.FileUtils:getInstance()
 7
 8 function fu.is_dir(filename)
 9     return string.byte(filename, -1) == 47
10 end
11
12 function fu.is_absolute_path(filename)
13     return cc_fileutils_:isAbsolutePath(filename)
14 end
15
16 function fu.get_writable_path(filename)
17     if filename then
18         return platform.get_writable_path() .. filename
19     end
20     return platform.get_writable_path()
21 end
22
23 function fu.get_full_path(filename)
24     return cc_fileutils_:fullPathForFilename(filename)
25 end
26
27 function fu.get_string(filename)
28     return cc_fileutils_:getStringFromFile(filename)
29 end
30
31 function fu.write_content(filename, content, mode)
32     mode = mode or "w+b"
33     local file = io.open(filename, mode)
34     if file then
35         if file:write(content) == nil then
36             return false
37         end
38         io.close(file)
39         return true
40     else
41         return false
42     end
43 end
44
45 function fu.is_exists(filename)
46     if fu.is_dir(filename) then
47         return cc_fileutils_:isDirectoryExist(filename)
48     end
49     return cc_fileutils_:isFileExist(filename)
50 end
51
52 function fu.make_dir(dirname)
53     return cc_fileutils_:createDirectory(dirname)
54 end
55
56 function fu.remove(filename)
57     if fu.is_dir(filename) then
58         return cc_fileutils_:removeDirectory(filename)
59     end
60     return cc_fileutils_:removeFile(filename)
61 end
62
63 function fu.rename_file(dir, old, new)
64     return cc_fileutils_:renameFile(dir, old, new)
65 end
66
67 function fu.get_file_size(filename)
68     return cc_fileutils_:getFileSize(filename)
69 end
70
71 return fu

fileutil.lua

2.添加了跨平台部分的文件存储处理,主要是处理writablepath.这个在platform.lua中,很快我就会写到增量动态更新模块,我期望在windows下面存储的路径就是res/,而在android下面则是writablepath.所以这个修改也是为了这部分功能先行的.源码如下:

 1 -- 小岩<[email protected]>
 2 -- 2015-5-25
 3 local p = {}
 4
 5 local OS_NAME =
 6 {
 7     "WINDOWS",
 8     "LINUX",
 9     "MAC",
10     "ANDROID",
11     "IPHONE",
12     "IPAD",
13     "BLACKBERRY",
14     "NACL",
15     "EMSCRIPTEN",
16     "TIZEN",
17     "WINRT",
18     "WP8",
19 }
20
21 local arch_code = cc.Application:getInstance():getTargetPlatform()
22 local arch_name = OS_NAME[arch_code+1]
23
24 p.arch_code = arch_code
25 p.arch_name = arch_name
26
27 function p.get_writable_path()
28     if p.arch_code == cc.PLATFORM_OS_WINDOWS then
29         return "res/"
30     else
31         return cc.FileUtils:getInstance():getWritablePath()
32     end
33 end
34
35 return p

platform.lua

3.处理各种配置文件,我暂时添加了四种,k-v有两种,ini格式,csv格式,准确的说是三种,不过我提供的classickv是支持lua语法的,因为本质上就是使用luastring返回的函数生成的,所以可以直接在其中使用lua语法,如果是使用sublime,可以直接ctrl+shift+p, 然后输入set synatax:lua去直接编辑配置文件.不过很快我就会再次介绍这种使用lua语法的好处,用在启动引擎的各种参数上面再好不过了.下面我就一一给出这四个文件.不过首先得看convert.lua 这个其实就是各加载到内存的配置字符串,解析成为对应的lua table.

  1 -- 小岩<[email protected]>
  2 -- 2015-5-25
  3 local c = {}
  4
  5 c.t =
  6 {
  7     kv     = "key-value format",
  8     ini = "section-key-value format",
  9     csv = "export csv format",
 10     classickv = "classic key-value format",
 11 }
 12
 13 local function lua_split(str, reps)
 14     local str_list = {}
 15     string.gsub(str, ‘[^‘ .. reps ..‘]+‘, function(w)
 16             table.insert(str_list, w)
 17         end)
 18     return str_list
 19 end
 20
 21 function c.c2t(content, type, ...)
 22     if type == c.t.kv then
 23         return c.c2t_kv(content, ...)
 24     elseif type == c.t.ini then
 25         return c.c2t_ini(content, ...)
 26     elseif type == c.t.csv then
 27         return c.c2t_csv(content, ...)
 28     elseif type == c.t.classickv then
 29         return c.c2t_kv(content)
 30     end
 31     return "unsupport-format"
 32 end
 33
 34 function c.c2t_kv(content, sep, l_sep)
 35     sep   = sep or "="
 36     l_sep = l_sep or "\r\n"
 37
 38     local ret = {}
 39     for _, line in ipairs(lua_split(content, l_sep)) do
 40         local k,v = line:match(‘^([%w_]+)%s-‘ .. sep .. ‘%s-(.+)$‘)
 41         if k then
 42             if not v then
 43                 v = ""
 44             end
 45             if tonumber(v) then
 46                 v =tonumber(v)
 47             elseif v == "true" then
 48                 v = true
 49             elseif v == "false" then
 50                 v = false
 51             end
 52             ret[k] = v
 53         end
 54     end
 55     return ret
 56 end
 57
 58 function c.c2t_classickv(content)
 59     return loadstring("return {" .. content .. "}")()
 60 end
 61
 62 function c.c2t_ini(content, sl_sep, sr_sep, kv_sep, l_sep)
 63     sl_sep = sl_sep or "["
 64     sr_sep = sr_sep or "]"
 65     kv_sep = kv_sep or "="
 66     l_sep  = l_sep or "\r\n"
 67
 68     local ret = {}
 69     local sec
 70     for _, line in ipairs(lua_split(content, l_sep)) do
 71         local section = line:match(‘^%‘ .. sl_sep ..  ‘([^%]]+)%‘ .. sr_sep .. ‘$‘)
 72         if section then
 73             sec = section
 74             ret[sec] = ret[sec] or {}
 75         end
 76
 77         local k,v = line:match(‘^([%w_]+)%s-‘ .. kv_sep .. ‘%s-(.+)$‘)
 78         if k and v then
 79             if tonumber(v) then
 80                 v = tonumber(v)
 81             elseif v == "true" then
 82                 v = true
 83             elseif v == "false" then
 84                 v = false
 85             end
 86
 87             if sec then
 88                 ret[sec][k] = v
 89             end
 90         end
 91     end
 92
 93     return ret
 94 end
 95
 96 function c.c2t_csv(content, sep, l_sep)
 97     sep   = sep or ","
 98     l_sep = l_sep or "\r\n"
 99
100     local ct = lua_split(content, l_sep)
101     local headers = lua_split(ct[1], sep)
102     table.remove(ct, 1)
103
104     local ret = {}
105     local n = 1
106     for _, line in ipairs(ct) do
107         local vks = lua_split(line, sep)
108         ret[n] = {}
109         for j =1, #headers do
110             ret[n][headers[j]] = vks[j]
111         end
112         n = n + 1
113     end
114
115     return ret
116 end
117
118 function c.c2s(t, type, ...)
119     if type == c.t.kv then
120         return c.c2s_kv(t, ...)
121     elseif type == c.t.ini then
122         return c.c2s_ini(t, ...)
123     elseif type == c.t.csv then
124         return c.c2s_csv(t, ...)
125     elseif type == c.t.classickv then
126         return c.c2s_kv(t)
127     end
128     return "unsupport-format"
129 end
130
131 function c.c2s_kv(t, sep, l_sep)
132     sep   = sep or "="
133     l_sep = l_sep or "\r\n"
134     local content = ""
135     for k, v in pairs(t) do
136         content = content .. tostring(k) .. sep .. tostring(v) .. l_sep
137     end
138     return content
139 end
140
141 function c.c2s_ini(t, sl_sep, sr_sep, kv_sep, l_sep)
142     sl_sep = sl_sep or "["
143     sr_sep = sr_sep or "]"
144     kv_sep = kv_sep or "="
145     l_sep  = l_sep or "\r\n"
146
147     local content = ""
148     for s, kv in pairs(t) do
149         content = content .. sl_sep .. tostring(s) .. sr_sep .. l_sep
150         for k, v in pairs(kv) do
151             content = content .. tostring(k) .. kv_sep .. tostring(v) .. l_sep
152         end
153     end
154     return content
155 end
156
157 function c.c2s_csv(t, sep, l_sep)
158     sep   = sep or ","
159     l_sep = l_sep or "\r\n"
160
161     local content = ""
162     local header = ""
163     for index, kv in ipairs(t) do
164         for k, v in pairs(kv) do
165             if index == 1 then
166                 header = header .. tostring(k) .. sep
167             end
168             content = content .. tostring(v) .. sep
169         end
170         content = content .. l_sep
171     end
172
173     return l_sep .. header .. l_sep .. content
174 end
175
176 return c

convert.lua

 1 -- 小岩<[email protected]>
 2 -- 2015-5-26
 3 local fu       = require "fw.util.fileutil"
 4 local convert = require "fw.util.convert"
 5 local kv = class("kv")
 6
 7 function kv:ctor(filename, ...)
 8     self.filename_ = filename
 9     self.extra_cfg_ = {...}
10     self:init_with_file()
11 end
12
13 function kv:copy()
14     return clone(self)
15 end
16
17 function kv:init_with_file()
18     assert(self.filename_ and type(self.filename_) == "string",
19         string.format("ini assert error: init_with_file() - invalid param %s", self.filename_))
20     local file_content = fu.get_string(self.filename_)
21     self.props_ = convert.c2t(file_content, convert.t.kv, unpack(self.extra_cfg_))
22 end
23
24 function kv:get(k)
25     assert(k and type(k) == "string",
26         string.format("ini assert error: get() - invalid param %s", k))
27     return self.props_[k]
28 end
29
30 function kv:update(k, nv)
31     local ov = self.props_[k]
32     self.props_[k] = nv
33     return ov
34 end
35
36 function kv:save_2_path(new_filepath)
37     local old_filepath = self.filename_
38     local content = convert.c2s(self.props_, convert.t.kv, unpack(self.extra_cfg_))
39     if fu.write_content(new_filepath, content) then
40         self.filename_ = new_filepath
41         return old_filepath
42     end
43     return nil
44 end
45
46 function kv:save()
47     local content = convert.c2s(self.props_, convert.t.kv, unpack(self.extra_cfg_))
48     if fu.write_content(self.filename_, content) then
49         return true
50     end
51     return false
52 end
53
54 return kv

kv.lua

 1 --小岩<[email protected]>
 2 --2015-5-26
 3 local fu        = require "fw.util.fileutil"
 4 local convert = require "fw.util.convert"
 5 local classickv = class("classickv")
 6
 7 function classickv:ctor(filename)
 8     self.filename_  = filename
 9     self:init_with_file()
10 end
11
12 function classickv:copy()
13     return clone(self)
14 end
15
16 function classickv:init_with_file()
17     assert(self.filename_ and type(self.filename_) == "string",
18         string.format("ini assert error: init_with_file() - invalid param %s", self.filename_))
19
20     local file_content = fu.get_string(self.filename_)
21     self.props_ = convert.c2t(file_content, convert.t.classickv)
22 end
23
24 function classickv:get(k)
25     assert(k and type(k) == "string",
26         string.format("ini assert error: get() - invalid param %s", k))
27     return self.props_[k]
28 end
29
30 function classickv:update(k, nv)
31     local ov = self.props_[k]
32     self.props_[k] = nv
33     return ov
34 end
35
36 function classickv:save_2_path(new_filepath)
37     local old_filepath = self.filename_
38     local content = convert.c2s(self.props_, convert.t.classickv)
39     if fu.write_content(new_filepath, content) then
40         self.filename_ = new_filepath
41         return old_filepath
42     end
43     return nil
44 end
45
46 function classickv:save()
47     local content = convert.c2s(self.props_, convert.t.classickv)
48     if fu.write_content(self.filename_, content) then
49         return true
50     end
51     return false
52 end
53
54 return classickv

classickv.lua

-- 小岩<[email protected]>
-- 2015-5-25
local fu        = require "fw.util.fileutil"
local convert = require "fw.util.convert"
local ini = class("ini")

function ini:ctor(filename, ...)
    self.filename_ = filename or nil
    self.extra_cfg_ = {...}
    self:init_with_file()
end

function ini:copy()
    return clone(self)
end

function ini:init_with_file()
    assert(self.filename_ and type(self.filename_) == "string",
        string.format("ini assert error: init_with_file() - invalid param %s", self.filename_))

    local file_content = fu.get_string(self.filename_)
    self.props_ = convert.c2t(file_content, convert.t.ini, unpack(self.extra_cfg_))
end

function ini:get(s, k)
    assert(s and type(s) == "string",
        string.format("ini assert error: get() - invalid param %s", s))
    assert(k and type(k) == "string",
        string.format("ini assert error: get() - invalid param %s", k))

    if self.props_[s] then
        return self.props_[s][k]
    else
        return nil
    end
end

function ini:update(s,k,nv)
    if not self.props_[s] then
        self.props_[s] = {}
    end
    local ov = self.props_[s][k]
    self.props_[s][k] = nv
    return ov
end

function ini:save_2_path(new_filepath)
    local old_filepath = self.filename_
    local content = convert.c2s(self.props_, convert.t.ini, unpack(self.extra_cfg_))
    if fu.write_content(new_filepath, content) then
        self.filename_ = new_filepath
        return old_filepath
    end
    return nil
end

function ini:save()
    local content = convert.c2s(self.props_, convert.t.ini, unpack(self.extra_cfg_))
    if fu.write_content(self.filename_, content) then
        return true
    end
    return false
end

return ini

ini.lua

 1 -- 小岩<[email protected]>
 2 -- 2015-5-25
 3 local fu        = require "fw.util.fileutil"
 4 local convert = require "fw.util.convert"
 5 local csv = class("csv")
 6
 7 function csv:ctor(filename, ...)
 8     self.filename_ = filename
 9     self.extra_cfg_ = {...}
10     self:init_with_file()
11 end
12
13 function csv:copy()
14     return clone(self)
15 end
16
17 function csv:init_with_file()
18     assert(self.filename_ and type(self.filename_) == "string",
19         string.format("ini assert error: init_with_file() - invalid param %s", self.filename_))
20
21     local file_content = fu.get_string(self.filename_)
22     self.props_ = convert.c2t(file_content, convert.t.csv, unpack(self.extra_cfg_))
23 end
24
25 function csv:get(n, k)
26     if self.props_[n] then
27         return self.props_[n][k]
28     else
29         return nil
30     end
31 end
32
33 function csv:update(n, k, nv)
34     if not self.props_[n] then
35         return nil
36     end
37     local ov = self.props_[n][k]
38     self.props_[n][k] = nv
39     return ov
40 end
41
42 function csv:save_2_path(new_filepath)
43     local old_filepath = self.filename_
44     local content = convert.c2s(self.props_, convert.t.csv, unpack(self.extra_cfg_))
45     if fu.write_content(new_filepath, content) then
46         self.filename_ = new_filepath
47         return old_filepath
48     end
49     return nil
50 end
51
52 function csv:save()
53     local content = convert.c2s(self.props_, convert.t.csv, unpack(self.extra_cfg_))
54     if fu.write_content(self.filename_, content) then
55         return true
56     end
57     return false
58 end
59
60 return csv

csv.lua

我在每一个针对配置文件的操作oop实现table中都提供了从文件读取以及持久化到文件的方法.不过如果使用lua sytax方式的classic.那么在持久化的时候并不能如期的解析table,这也是当初我没有注意到的问题,不过后来我想了一下,如果是需要持久化的数据,那么我都会使用基本数据类型.所以这个不会影响我的使用.好的,另外一点需要注意的是,读取文件的接口我并没有使用lua的io接口,这是因为lua默认还是有环境变量的,不能够读取apk压缩包中的配置,所以我还是使用cc.fileutils中的接口.

好的,早上总结了一下昨天完成的内容. 接下来考虑实现那一块先.

时间: 2024-10-01 03:40:05

`cocos2dx非完整` 开始自己的FW模块的相关文章

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

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

`cocos2dx 非完整` UI解析模块

昨天在cocos2dx的一个群里,遇到一位匿名为x的朋友询问的问题,是关于ui的.他使用c++写了不少的ui封装节点,用来实现游戏中的各种不同效果.然后现在想改用lua,于是尝试使用最小代价去复用自己的代码.当然这个是可以做到的,相信很多人都是知道方法的.今天的这篇文章就来谈谈ui部分的处理以及个人的见解. 我们都知道,cocos2dx引擎提供了ui工具cocostudio.后来改名为cocos engine.这些就不赘述了,很多人都会使用这款工具.新版本的工具我没有使用过,不过我承认是方便了很

`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非完整` 游戏架构缩影 添加启动流程

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

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

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

Cocos2d-x源代码解析(1)——地图模块(3)

接上一章<Cocos2d-x源代码解析(1)--地图模块(2)> 通过前面两章的分析,我们能够知道cocos将tmx的信息结构化到 CCTMXMapInfo.CCTMXTilesetInfo,CCTMXLayerInfo之中. 当中CCTMXMapInfo存储地图的信息包扩下面几块信息: - Map orientation (hexagonal, isometric or orthogonal) - Tile size - Map size - Layers (an array of TMXL

机器学习 —— 概率图模型(学习:非完整数据)

1.综述 PGM的学习问题实际上是对参数进行推断.对于给定的数据,需要求出系统参数,从而完善系统的CPD.但是某些情况下,PGM的数据集可能是不完整的.数据集不完整可以分为两种情况:1.数据采集受到了影响:2.使用了隐变量.数据采集受到影响可能出于两种情况,第一种是影响与被采集数据是无关的,例如投硬币,结果硬币找不到了.第二种是和被采集数据有关的,例如在收发数据时,高电平总是踩空.故在使用不完整的数据对模型进行训练之前,需要对造成不完整的原因进行判断.如果对上述两种情况进行建模,则有以下图模型:

seajs2.3学习日志 简单尝试模板+数据合并、模块异步加载、非标准CMD模式定义define模块

今天继续尝试seajs 2.3的版本,那做点什么demo好呢,就来一个简单是数据模板吧,然后通过其他一些细节深入学习 先看看目录结构,按照官方demo架设 index.html只是简单入口文件和seajs的配置项,最下面有一个seajs.use加载crontroller模块,然后回调暴露的combine方法 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>

cocos2d-x入门一

为什么要学cocos2d-x 首先要明白什么是cocos2d-x,能干什么.cocos2d-x是一种跨平台的2D.3D游戏开发工具,目前较为流行的大多数android.ios游戏都是用它开发的.它跨平台特性,是因为它OpenGL是跨平台的,当然它不仅包含OpenGL,还有其它平台上的图形处理接口,因此它是跨平台的. 针对自己因素,自己目前对C++比较熟,而cocos2d-x与C++的关系目前还不是特别清晰,但是与C++相关度比较大,而且是游戏方面的,比较有意思.关键是还与当前的大行业趋势移动开发