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

时间:2022-04-16 17:18:52

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

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

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

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

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

 -- 小岩<@qq.com>
-- -- :
cc.FileUtils:getInstance():addSearchPath("res")
cc.FileUtils:getInstance():addSearchPath("src") require "cocos.init"
local fw = require "fw.init" function __G__TRACKBACK__(msg)
print("lua error: " .. tostring(msg) .. "\n")
print(debug.traceback())
return msg
end local function main()
collectgarbage("collect")
-- avoid memory leak
collectgarbage("setpause", )
collectgarbage("setstepmul", ) -- initialize director
local director = cc.Director:getInstance()
local glview = director:getOpenGLView()
if nil == glview then
glview = cc.GLViewImpl:createWithRect("HelloLua", cc.rect(,,,))
director:setOpenGLView(glview)
end glview:setDesignResolutionSize(, , cc.ResolutionPolicy.NO_BORDER) --turn on display FPS
director:setDisplayStats(true) --set FPS. the default value is 1.0/ if you don't call this
director:setAnimationInterval(1.0 / ) end local status, msg = xpcall(main, __G__TRACKBACK__)
if not status then
error(msg)
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中,并添加了部分自己的功能,源码如下:

 -- 小岩<757011285@qq.com>
-- 2015-5-25
local platform = require "fw.util.platform" local fu = {}
local cc_fileutils_ = cc.FileUtils:getInstance() function fu.is_dir(filename)
return string.byte(filename, -) ==
end function fu.is_absolute_path(filename)
return cc_fileutils_:isAbsolutePath(filename)
end function fu.get_writable_path(filename)
if filename then
return platform.get_writable_path() .. filename
end
return platform.get_writable_path()
end function fu.get_full_path(filename)
return cc_fileutils_:fullPathForFilename(filename)
end function fu.get_string(filename)
return cc_fileutils_:getStringFromFile(filename)
end function fu.write_content(filename, content, mode)
mode = mode or "w+b"
local file = io.open(filename, mode)
if file then
if file:write(content) == nil then
return false
end
io.close(file)
return true
else
return false
end
end function fu.is_exists(filename)
if fu.is_dir(filename) then
return cc_fileutils_:isDirectoryExist(filename)
end
return cc_fileutils_:isFileExist(filename)
end function fu.make_dir(dirname)
return cc_fileutils_:createDirectory(dirname)
end function fu.remove(filename)
if fu.is_dir(filename) then
return cc_fileutils_:removeDirectory(filename)
end
return cc_fileutils_:removeFile(filename)
end function fu.rename_file(dir, old, new)
return cc_fileutils_:renameFile(dir, old, new)
end function fu.get_file_size(filename)
return cc_fileutils_:getFileSize(filename)
end return fu

fileutil.lua

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

 -- 小岩<757011285@qq.com>
-- 2015-5-25
local p = {} local OS_NAME =
{
"WINDOWS",
"LINUX",
"MAC",
"ANDROID",
"IPHONE",
"IPAD",
"BLACKBERRY",
"NACL",
"EMSCRIPTEN",
"TIZEN",
"WINRT",
"WP8",
} local arch_code = cc.Application:getInstance():getTargetPlatform()
local arch_name = OS_NAME[arch_code+] p.arch_code = arch_code
p.arch_name = arch_name function p.get_writable_path()
if p.arch_code == cc.PLATFORM_OS_WINDOWS then
return "res/"
else
return cc.FileUtils:getInstance():getWritablePath()
end
end 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.

 -- 小岩<757011285@qq.com>
-- 2015-5-25
local c = {} c.t =
{
kv = "key-value format",
ini = "section-key-value format",
csv = "export csv format",
classickv = "classic key-value format",
} local function lua_split(str, reps)
local str_list = {}
string.gsub(str, '[^' .. reps ..']+', function(w)
table.insert(str_list, w)
end)
return str_list
end function c.c2t(content, type, ...)
if type == c.t.kv then
return c.c2t_kv(content, ...)
elseif type == c.t.ini then
return c.c2t_ini(content, ...)
elseif type == c.t.csv then
return c.c2t_csv(content, ...)
elseif type == c.t.classickv then
return c.c2t_kv(content)
end
return "unsupport-format"
end function c.c2t_kv(content, sep, l_sep)
sep = sep or "="
l_sep = l_sep or "\r\n" local ret = {}
for _, line in ipairs(lua_split(content, l_sep)) do
local k,v = line:match('^([%w_]+)%s-' .. sep .. '%s-(.+)$')
if k then
if not v then
v = ""
end
if tonumber(v) then
v =tonumber(v)
elseif v == "true" then
v = true
elseif v == "false" then
v = false
end
ret[k] = v
end
end
return ret
end function c.c2t_classickv(content)
return loadstring("return {" .. content .. "}")()
end function c.c2t_ini(content, sl_sep, sr_sep, kv_sep, l_sep)
sl_sep = sl_sep or "["
sr_sep = sr_sep or "]"
kv_sep = kv_sep or "="
l_sep = l_sep or "\r\n" local ret = {}
local sec
for _, line in ipairs(lua_split(content, l_sep)) do
local section = line:match('^%' .. sl_sep .. '([^%]]+)%' .. sr_sep .. '$')
if section then
sec = section
ret[sec] = ret[sec] or {}
end local k,v = line:match('^([%w_]+)%s-' .. kv_sep .. '%s-(.+)$')
if k and v then
if tonumber(v) then
v = tonumber(v)
elseif v == "true" then
v = true
elseif v == "false" then
v = false
end if sec then
ret[sec][k] = v
end
end
end return ret
end function c.c2t_csv(content, sep, l_sep)
sep = sep or ","
l_sep = l_sep or "\r\n" local ct = lua_split(content, l_sep)
local headers = lua_split(ct[], sep)
table.remove(ct, ) local ret = {}
local n =
for _, line in ipairs(ct) do
local vks = lua_split(line, sep)
ret[n] = {}
for j =, #headers do
ret[n][headers[j]] = vks[j]
end
n = n +
end return ret
end function c.c2s(t, type, ...)
if type == c.t.kv then
return c.c2s_kv(t, ...)
elseif type == c.t.ini then
return c.c2s_ini(t, ...)
elseif type == c.t.csv then
return c.c2s_csv(t, ...)
elseif type == c.t.classickv then
return c.c2s_kv(t)
end
return "unsupport-format"
end function c.c2s_kv(t, sep, l_sep)
sep = sep or "="
l_sep = l_sep or "\r\n"
local content = ""
for k, v in pairs(t) do
content = content .. tostring(k) .. sep .. tostring(v) .. l_sep
end
return content
end function c.c2s_ini(t, sl_sep, sr_sep, kv_sep, l_sep)
sl_sep = sl_sep or "["
sr_sep = sr_sep or "]"
kv_sep = kv_sep or "="
l_sep = l_sep or "\r\n" local content = ""
for s, kv in pairs(t) do
content = content .. sl_sep .. tostring(s) .. sr_sep .. l_sep
for k, v in pairs(kv) do
content = content .. tostring(k) .. kv_sep .. tostring(v) .. l_sep
end
end
return content
end function c.c2s_csv(t, sep, l_sep)
sep = sep or ","
l_sep = l_sep or "\r\n" local content = ""
local header = ""
for index, kv in ipairs(t) do
for k, v in pairs(kv) do
if index == then
header = header .. tostring(k) .. sep
end
content = content .. tostring(v) .. sep
end
content = content .. l_sep
end return l_sep .. header .. l_sep .. content
end return c

convert.lua

 -- 小岩<757011285@qq.com>
-- 2015-5-26
local fu = require "fw.util.fileutil"
local convert = require "fw.util.convert"
local kv = class("kv") function kv:ctor(filename, ...)
self.filename_ = filename
self.extra_cfg_ = {...}
self:init_with_file()
end function kv:copy()
return clone(self)
end function kv: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.kv, unpack(self.extra_cfg_))
end function kv:get(k)
assert(k and type(k) == "string",
string.format("ini assert error: get() - invalid param %s", k))
return self.props_[k]
end function kv:update(k, nv)
local ov = self.props_[k]
self.props_[k] = nv
return ov
end function kv:save_2_path(new_filepath)
local old_filepath = self.filename_
local content = convert.c2s(self.props_, convert.t.kv, unpack(self.extra_cfg_))
if fu.write_content(new_filepath, content) then
self.filename_ = new_filepath
return old_filepath
end
return nil
end function kv:save()
local content = convert.c2s(self.props_, convert.t.kv, unpack(self.extra_cfg_))
if fu.write_content(self.filename_, content) then
return true
end
return false
end return kv

kv.lua

 --小岩<757011285@qq.com>
--2015-5-26
local fu = require "fw.util.fileutil"
local convert = require "fw.util.convert"
local classickv = class("classickv") function classickv:ctor(filename)
self.filename_ = filename
self:init_with_file()
end function classickv:copy()
return clone(self)
end function classickv: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.classickv)
end function classickv:get(k)
assert(k and type(k) == "string",
string.format("ini assert error: get() - invalid param %s", k))
return self.props_[k]
end function classickv:update(k, nv)
local ov = self.props_[k]
self.props_[k] = nv
return ov
end function classickv:save_2_path(new_filepath)
local old_filepath = self.filename_
local content = convert.c2s(self.props_, convert.t.classickv)
if fu.write_content(new_filepath, content) then
self.filename_ = new_filepath
return old_filepath
end
return nil
end function classickv:save()
local content = convert.c2s(self.props_, convert.t.classickv)
if fu.write_content(self.filename_, content) then
return true
end
return false
end return classickv

classickv.lua

-- 小岩<757011285@qq.com>
-- 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

 -- 小岩<757011285@qq.com>
-- 2015-5-25
local fu = require "fw.util.fileutil"
local convert = require "fw.util.convert"
local csv = class("csv") function csv:ctor(filename, ...)
self.filename_ = filename
self.extra_cfg_ = {...}
self:init_with_file()
end function csv:copy()
return clone(self)
end function csv: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.csv, unpack(self.extra_cfg_))
end function csv:get(n, k)
if self.props_[n] then
return self.props_[n][k]
else
return nil
end
end function csv:update(n, k, nv)
if not self.props_[n] then
return nil
end
local ov = self.props_[n][k]
self.props_[n][k] = nv
return ov
end function csv:save_2_path(new_filepath)
local old_filepath = self.filename_
local content = convert.c2s(self.props_, convert.t.csv, unpack(self.extra_cfg_))
if fu.write_content(new_filepath, content) then
self.filename_ = new_filepath
return old_filepath
end
return nil
end function csv:save()
local content = convert.c2s(self.props_, convert.t.csv, unpack(self.extra_cfg_))
if fu.write_content(self.filename_, content) then
return true
end
return false
end return csv

csv.lua

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

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