用qt读写操作cocos studio UI数据文件(xml)

qt是一个功能很强大的c++库,其中就支持xml文件的读写,今天我们就Dom的方式来读写cocos studio 的ui数据文件(还有一种SAX方式)
cocos studio ui数据文件(及时.csd格式的)就是一个标准的xml文档,其描述的cocos2d-x引擎中的所用ui元素及其相关属性,我们就用qt读取并操作csd文件,将所有的text UI元素都变成有黑色描边像素为2的字体
下面展示一个目标文件
[xml]
<GameProjectFile>
<PropertyGroup Type="Layer" Name="l_rolename" ID="f6121bb9-8449-4d10-a3ec-ac853464229a" Version="2.3.2.3" />
<Content ctype="GameProjectContent">
<Content>
<Animation Duration="0" Speed="1.0000" />
<ObjectData Name="Layer" Tag="4278" ctype="GameLayerObjectData">
<Size X="72.0000" Y="24.0000" />
<Children>
<AbstractNodeData Name="ListView" ActionTag="1039694078" Tag="294" IconVisible="False" RightMargin="-128.0000" TopMargin="-8.0000" BackColorAlpha="102" ColorAngle="90.0000" ScrollDirectionType="0" ctype="ListViewObjectData">
<Size X="200.0000" Y="32.0000" />
<Children>
<AbstractNodeData Name="Text_Name" ActionTag="-1681367417" Tag="4279" IconVisible="False" RightMargin="152.0000" TopMargin="12.0000" FontSize="24" LabelText="名字" HorizontalAlignmentType="HT_Center" VerticalAlignmentType="VT_Bottom" OutlineSize="2" OutlineEnabled="True" ShadowOffsetX="0.0000" ShadowOffsetY="0.0000" ctype="TextObjectData">
<Size X="50.0000" Y="32.0000" />
<AnchorPoint />
<Position />
<Scale ScaleX="1.0000" ScaleY="1.0000" />
<CColor A="255" R="255" G="255" B="255" />
<PrePosition />
<PreSize X="0.0000" Y="0.0000" />
<FontResource Type="Normal" Path="fonts/wqyhei.ttf" Plist="" />
<OutlineColor A="255" R="0" G="0" B="0" />
<ShadowColor A="255" R="110" G="110" B="110" />
</AbstractNodeData>
<AbstractNodeData Name="Text_Add" ActionTag="150656575" ZOrder="1" Tag="295" IconVisible="False" LeftMargin="48.0000" RightMargin="134.0000" TopMargin="1.0000" FontSize="24" LabelText="+" OutlineSize="2" OutlineEnabled="True" ShadowOffsetX="0.0000" ShadowOffsetY="0.0000" ctype="TextObjectData"><!– 目标ui元素 TextObjectData–>
<Size X="18.0000" Y="32.0000" />
<AnchorPoint ScaleX="0.5000" ScaleY="0.5000" />
<Position X="59.0000" Y="16.0000" />
<Scale ScaleX="1.0000" ScaleY="1.0000" />
<CColor A="255" R="255" G="255" B="255" />
<PrePosition X="0.2850" Y="0.4875" />
<PreSize X="0.0000" Y="0.0000" />
<FontResource Type="Normal" Path="fonts/wqyhei.ttf" Plist="" />
<OutlineColor A="255" R="0" G="0" B="0" />
<ShadowColor A="255" R="110" G="110" B="110" />
</AbstractNodeData>
<AbstractNodeData Name="Text_Stage" ActionTag="-1707735990" ZOrder="2" Tag="4280" IconVisible="False" LeftMargin="66.0000" RightMargin="119.0000" TopMargin="8.0000" FontSize="27" LabelText="1" HorizontalAlignmentType="HT_Center" VerticalAlignmentType="VT_Center" OutlineSize="2" OutlineEnabled="True" ShadowOffsetX="0.0000" ShadowOffsetY="0.0000" ctype="TextObjectData">
<Size X="13.0000" Y="35.0000" />
<AnchorPoint />
<Position X="68.0000" Y="-3.0000" />
<Scale ScaleX="1.0000" ScaleY="1.0000" />
<CColor A="255" R="255" G="255" B="255" />
<PrePosition X="0.3300" />
<PreSize X="0.0000" Y="0.0000" />
<FontResource Type="Normal" Path="fonts/wqyhei.ttf" Plist="" />
<OutlineColor A="255" R="0" G="0" B="0" />
<ShadowColor A="255" R="110" G="110" B="110" />
</AbstractNodeData>
</Children>
<AnchorPoint />
<Position />
<Scale ScaleX="1.0000" ScaleY="1.0000" />
<CColor A="255" R="255" G="255" B="255" />
<PrePosition />
<PreSize X="2.7778" Y="1.3333" />
<SingleColor A="255" R="150" G="150" B="255" />
<FirstColor A="255" R="150" G="150" B="255" />
<EndColor A="255" R="255" G="255" B="255" />
<ColorVector ScaleY="1.0000" />
</AbstractNodeData>
</Children>
</ObjectData>
</Content>
</Content>
</GameProjectFile>
[/xml]

在这段文本中 ctype=”TextObjectData” 的元素的就是我们的要找到并修改的ui元素

我们建个qt ui 工程。在.pro文件中添加 QT += xml 引入xml解析库

[cpp]
#include"mainwindow.h"
#include"ui_mainwindow.h"
MainWindow::MainWindow(QWidget*parent):
QMainWindow(parent),
ui(newUi::MainWindow)
{
ui->setupUi(this);
this->ShowFiles(1,"D:/qtworkspace/change_text_outline/cocosstudio"); //传入所有csd文件路径
}

MainWindow::~MainWindow()
{
deleteui;
}

boolMainWindow::matchLine(QStringpath)
{
bool ret=false;
QFile file(path);
if(!file.open(QIODevice::ReadWrite|QIODevice::Text))
{
return1;
}

QTextStream in(&file);//文本流操作

QString line=in.readAll();//读取到字符串
QDomDocument document;//dom 对象
QString strError;
int errLin=0,errCol=0;
if(!document.setContent(line,false,&strError,&errLin,&errCol))//设置dom内容,并做失败处理
{
printf("parsefilefailedatline%dcolumn%d,error:%s!\n",errLin,errCol,strError);
return false;
}

if(document.isNull())
{
printf("documentisnull!\n");
return false;
}

QDomElement root=document.documentElement();

this->changeItem(root);

QFile f(path);//重新打开文件将更改后的文本写入
if(!f.open(QFile::WriteOnly|QFile::Text))
return false;
QTextStream out(&f);
document.save(out,4);//写入保存
f.close();

file.close();
return ret;
}
voidMainWindow::changeItem(QDomElement&elementRef)//查找目标节点并更改属性
{
QDomElement element=elementRef.firstChildElement();//获取该节点的第一个子节点
while(!element.isNull()){//遍历子节点
if(element.hasAttribute("ctype"))
{
if(element.attributeNode("ctype").value().toStdString()=="TextObjectData") //找到ctype == TextObjectData的节点
{
this->isChange=true;
qDebug()<<element.attributeNode("ctype").value().toStdString().c_str();
element.setAttribute("OutlineSize",2);
element.setAttribute("OutlineEnabled","True");
QDomElement nodec=element.namedItem("OutlineColor").toElement(); //获取到描边属性节点
if(!nodec.isNull())
{
nodec.setAttribute("A",255); //设置描边颜色
nodec.setAttribute("R",0);
nodec.setAttribute("B",0);
nodec.setAttribute("G",0);
}
}
}
this->changeItem(element);//因为ui控有可能是嵌套的所以递归处理子节点
element=element.nextSiblingElement();
}

}
voidMainWindow::ShowFiles(intlevel,constQString&path)//递归遍历文件夹及其下面的文件
{
//这个函数可以执行任何任务,
//这里只是简单地输出各个文件(夹)的名字
QDirdir(path);
QStringListlist;
QStringList::Iteratoriter;
QStringtemp(level,’-‘);

list=dir.entryList(QDir::Dirs,QDir::Name);
for(iter=list.begin();iter!=list.end();++iter)
{
if("."==*iter||
".."==*iter)
continue;
//qDebug()<<temp+*iter+"(folder)";
ShowFiles(level+1,path+"/"+*iter);
}

list=dir.entryList(QDir::Files,QDir::Name);
for(iter=list.begin();iter!=list.end();++iter)
{

QStringtempstr=path+"/"+*iter;
//this->labelOut->setText(tempstr);

//this->labelOut->setText(this->strOut);
if(tempstr.right(3)=="csd")
{
this->isChange=false;
matchLine(tempstr);
if(this->isChange)
{
qDebug()<<temp+path+"/"+*iter;
}
}
}
}

[/cpp]
这样我们就很方便的把所有的csd文件做了处理。理论上我们可以做很多处理,比如我们和以自动生成一些我们想要的ui模板等等,我们可以尽情的发挥想象了

cocos2d-x 3.7 实现图片按钮 过滤点击透明区域 在lua中使用

首先在widget头文件添加:
[cpp]
virtual bool AlphaTouchCheck(const Vec2 &point);
virtual bool getAlphaTouchEnable();
virtual void setAlphaTouchEnable(bool isAlphaTouch);
bool _isAlphaTouchEnable = true;
[/cpp]
在widget cpp文件中简单实现
[cpp]
bool Widget::AlphaTouchCheck(const Vec2 &point)
{
return true;
}

bool Widget::getAlphaTouchEnable()
{
return _isAlphaTouchEnable;
}

void Widget::setAlphaTouchEnable(bool isAlphaTouch)
{
_isAlphaTouchEnable = isAlphaTouch;
}
[/cpp]
widget中的判断先默认返回true

把开启的开关放在widget中,方便以后layout 和 imageview的不规则点击。开关默认关闭

接下来就是imageview中重载AlphaTouchCheck 函数
[cpp]
bool ImageView::AlphaTouchCheck(const Vec2& point)
{
if (getAlphaTouchEnable())
{
Image* normalImage = new Image();
normalImage->initWithImageFile(_normalImageString);
auto data = normalImage->getData();
if (data == NULL)
{
return true;
}
auto locationInNode = this->convertToNodeSpace(point);
//图片的0,0 是左上角 所以要和触摸点的Y转换一下 也就是“(normalImage->getHeight() – (int)(locationInNode.y) – 1)”
//该data值是把二维数组展开成一个一维数组, 因为每个像素值由RGBA组成, 所以每隔4个char为一个RGBA, 并且像素以横向排列
int pa = 4 * ((normalImage->getHeight() – (int)(locationInNode.y) – 1) * normalImage->getWidth() + (int)(locationInNode.x)) + 3;
unsigned int ap = data[pa];
if (ap < 20)
{
CC_SAFE_DELETE(normalImage);
return false;
}
else
{
CC_SAFE_DELETE(normalImage);
return true;
}
}
return true;
}
[/cpp]

std::string _normalImageString 是记录创建时候的图片名。

编译工程
接下来在lua中使用
[lua]
imageButton:addTouchEventListener(function(sender, type)
if type == ccui.TouchEventType.began then
self.beginPos = gFun.scene.getMousePos();
self.effect = true;
if imageButton:AlphaTouchCheck(gFun.scene.getMousePos()) then –传入鼠标点击位置
imageButton:setScale(0.95);
end
elseif type == ccui.TouchEventType.moved then
if getDistance(self.beginPos, gFun.scene.getMousePos()) > 20 then –判断是不是有滑动
self.effect = false;
end
elseif type == ccui.TouchEventType.canceled then

imageButton:setScale(1);
elseif type == ccui.TouchEventType.ended then
if not self.effect then return end

imageButton:setScale(1);
if imageButton:AlphaTouchCheck(gFun.scene.getMousePos()) then –传入鼠标点击位置
–do something;
end
end
end
)

[/lua]

让syntaxhighlighter 插件支持lua语言

wordpress 的代码高亮插件syntaxhighlighter是不支持lua脚本语言的,这个让读者看起lua代码来着实费劲,我抽空看了一下,只要扩展 syntaxhighlighter里面的shBrush 就好了,先贴出shBrushLua.js的代码
[js]
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != ‘undefined’ ? SyntaxHighlighter = require(‘shCore’).SyntaxHighlighter : null;

function Brush()
{
// maker is IkPil, Choi
// http://www.ikpil.com

var keywords = ‘and break do else elseif end false for function if in ‘ +
‘local nil not or repeat return then true until while’;

var functions = ‘_G _VERSION assert collectgarbage dofile error getfenv ‘ +
‘getmetatable ipairs load module next pairs pcall print ‘ +
‘ rawequal rawget rawset require select setfenv setmetatable ‘ +
‘tonumber tostring type unpack xpcall ‘ +
‘coroutine.create coroutine.resume coroutine.running ‘ +
‘coroutine.status coroutine.wrap coroutine.yield ‘ +
‘debug.debug debug.getfenv debug.gethook debug.getinfo ‘ +
‘debug.getlocal debug.getmetatable debug.getregistry ‘ +
‘debug.getupvalue debug.setfenv debug.sethook debug.setlocal ‘ +
‘debug.setmetatable debug.setupvalue debug.traceback ‘ +
‘file:close file:flush file:lines file:read file:seek ‘ +
‘file:setvbuf file:write’ +
‘io.close io.flush io.input io.lines io.open io.output ‘ +
‘io.popen io.read io.stderr io.stdin io.stdout io.tmpfile ‘ +
‘io.type io.write ‘ +
‘math.abs math.acos math.asin math.atan math.atan2 math.ceil ‘ +
‘math.cos math.cosh math.deg math.exp math.floor math.fmod ‘ +
‘math.frexp math.huge math.ldexp math.log math.log10 math.max ‘ +
‘math.min math.modf math.pi math.pow math.rad math.random ‘ +
‘math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh ‘ +
‘os.clock os.date os.difftime os.execute os.exit os.getenv os.remove ‘ +
‘os.rename os.setlocale os.time os.tmpname ‘ +
‘package.cpath package.loaded package.loaders package.loadlib ‘ +
‘package.path package.preload package.seeall ‘ +
‘string.byte string.char string.dump string.find string.format ‘ +
‘string.gmatch string.gsub string.len string.lower string.match ‘ +
‘string.rep string.reverse string.sub string.upper table.concat ‘ +
‘table.insert table.maxn table.remove table.sort’;

this.regexList = [
{ regex: /–.*/gm, css: ‘comments’ }, // one line comments
{ regex: /–\[\[[\S\s]*\]\]/gm, css: ‘comments’ }, // multi line comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: ‘string’ }, // strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: ‘string’ }, // strings
{ regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString, css: ‘string’ }, // strings
{ regex: SyntaxHighlighter.regexLib.multiLineSingleQuotedString, css: ‘string’ }, // strings
{ regex: new RegExp(this.getKeywords(keywords), ‘gm’), css: ‘keyword’ }, // keywords
{ regex: new RegExp(this.getKeywords(functions), ‘gm’), css: ‘functions’ } // functions
];
}

Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = [‘lua’];

SyntaxHighlighter.brushes.Lua = Brush;

// CommonJS
typeof(exports) != ‘undefined’ ? exports.Brush = Brush : null;
})();
[/js]
接下来就是把shBrushLua.js文件放到scripts 文件夹下面,现在shBrush就准备好了

最后就是修改SyntaxHighlighter插件的php的源码,把shBurshLua添加到shBrush;打开syntaxhighlighter.php文件找到如图位置
clipboard
插入下面一行代码
[php]
wp_register_script( ‘syntaxhighlighter-brush-lua’, plugins_url( $this->shfolder . ‘/scripts/shBrushLua.js’, __FILE__ ), array(‘syntaxhighlighter-core’), $this->agshver );
[/php]
找到$this->brushes = (array) apply_filters( ‘syntaxhighlighter_brushes’, array( 这里在数据组的最下面添加 ‘lua’ => ‘lua’, 如图clipboard2
保存就好了

让我们写段测试代码看一下效果
[lua]
function pirntTest()
for i = 1,10 do
print("hello world")
end
end
[/lua]

lua 代码调优profile 工具

cocos2d-x lua工程没自带的profile 工具,前段时间项目有好多代码的用时都要测试,所以就自己写了一个,在此贴出,有用的直接拿去,省的重复造车轮

[lua]
module("gProfiles", package.seeall)

local timerTab = {}

function ProfilingBeginTimingBlock(timerName)
if timerTab[timerName] then
timerTab[timerName].lastTime = os.clock()
else
timerTab[timerName] = {
count = 0,
minTime = 99999999999,
maxTime = 0,
totalTime = 0,
lastTime = os.clock(),
name = timerName
}
end

end
function ProfilingEndTimingBlock(timerName)
local data = timerTab[timerName]
if data then

local deltaTime = os.clock() – data.lastTime
data.totalTime = data.totalTime + deltaTime
data.count = data.count + 1
if data.minTime >= deltaTime then
data.minTime = deltaTime
end
if data.maxTime <= deltaTime then
data.maxTime = deltaTime
end
else
error("timerName error!!!")
end

end
function displayTimers()
print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ profiles start ")
for k,v in pairs(timerTab) do
print(tostring(v.name));
print(string.format("%s—%f","count",v.count));
print(string.format("%s—%f","minTime",v.minTime)) ;
print(string.format("%s—%f","maxTime",v.maxTime));
print(string.format("%s—%f","totalTime",v.totalTime));
print(string.format("%s—%f","averageTime",v.totalTime/v.count)) ;
print("———————————————")
end
print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ profiles end ")
end

–dome code
–[[

gProfiles.ProfilingBeginTimingBlock("initRoleList")
self:initRoleList()
gProfiles.ProfilingEndTimingBlock("initRoleList")

gProfiles.displayTimers()
–]]

[/lua]
require() 一下就可以使用了