1.Excel和2dx有何关系?
大部分的游戏数值策划都会用excel表来做数据。那么在我们的客户端还没有开发网络功能或者服务端还没开发完的时候,已经需要数据来进行战斗测试了,如何快速把策划用excel做的数值表在cocos2d-x开发的游戏中调用呢?答案是XML。流程是这样的:Excel表导出XML格式,然后用cocos2d-x已经集成的tinyXML来解析,看上去很简单,不是吗?
当然事情每每深入下去,就会发现有许多细节值得推敲。比如,XML的组织有两种形式,一种是把数据当成节点的值:
<item>
<id>1</id>
<x>2</x>
<y>3</y>
<att>40</att>
<def>10</def>
<hp>300</hp>
<eng>120</eng>
</item>
另外一种是把数据当成属性的:
<role id="1" x="1" y="1" att="80" def="14" hp="330" eng="29" attcnt="0" defcnt="0" flex="131" lv="1" exp="10" etc="1"/>
哪一种好呢?你可能会看到许多文章说第二种做法是sb啊什么的,而我认为如果节点不需要嵌套,那么显然第二种更简洁,也更符合二维表的特性。更重要的是,在TinyXML的操作中,没有提供一个方法直接访问名字为id的节点,我们必须遍历各个子节点然后if(strcmp(pNode->Value(), "id")==0)来查找节点再getText取值,显然蛋疼,而属性则只要std::string valueIwant = pNode->Attirbute("id")就已经把值以string的格式取到了,高下立判!
2.怎么按自己的想法导出excel?
要让策划一键导出上面第二种形式的XML文件,就必须使用XSD文件,也就是XML 的格式定义文件,具体这么写:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="item">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="role" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:positiveInteger"/>
<xsd:attribute name="x" type="xsd:positiveInteger"/>
<xsd:attribute name="y" type="xsd:positiveInteger"/>
<xsd:attribute name="att" type="xsd:positiveInteger"/>
<xsd:attribute name="def" type="xsd:positiveInteger"/>
<xsd:attribute name="hp" type="xsd:positiveInteger"/>
<xsd:attribute name="eng" type="xsd:positiveInteger"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
保存成后缀为xsd的文件,比如“dataformat.xsd”,然后打开excel,如下图把xsd当成XML的映射源。记得右键“映射元素”把数据全选,最后按图中导出按钮,成功导出。
3.在cocos2d-x里面调用
在得到我们以指定形式组织数据的的XML文件之后,就需要调用。打开2.1.4或3.0源文件中的的CCUserDefault.cpp和CCUserDefault.h,我们可以清楚的看到里面使用的是TinyXML这个库,马上拿来主义,修改一下。CCUserDefault是一个单例类,同时里面包含了读写当前文件的全局静态函数。那么根据需要,我们可以把CCUserDefault类和这两个全局静态函数山寨一下,之后用这个山寨类来读写指定的XML文件。注意在安卓上,把XML放在assets之后,直接用FileUtils::getInstance()->getWritablePath() + XML_FILE_NAME是读取不到的,必须copy一份出来,具体请参考其他文章,比如
这篇
那么我们一般在win32下读取xml数据进行测试时,只要把xml文件放在Debug.32里面就好了。在本例中我们用id这个属性来判断是否找到需要的节点,那么静态方法可以这么改一下,把static tinyxml2::XMLElement* getXMLNodeForKey中的这一段
while (NULL != curNode)
{
const char* nodeName = curNode->Value();
if (!strcmp(nodeName, pKey))
{
break;
}
curNode = curNode->NextSiblingElement();
}
改成
while (NULL != curNode)
{
std::string nodeId = curNode->Attribute("id");
if (!strcmp(nodeId.c_str(), pKey))
{
break;
}
curNode = curNode->NextSiblingElement();
}
你也可以多加一个const char*参数把需要获取的Attribute的名字传进去,这样就更灵活了。返回了需要的节点curNode之后,可以在我们那个山寨类里面写读写的函数。读取上面已经说了,写就是curNode->SetAttribute("x","1")。
于是我们就可以很快速的套上数值策划给的数值进行战斗测试了!
若有兴趣可加群一起交流,速成cocos2d-x学习交流qq群:323635541