#
一切又归零了。不解释什么! 无所谓得,无所谓失 有任性,有责任 2016终于开始。
本文地址:http://www.cppblog.com/zdhsoft/archive/2014/09/03/208216.html 本文基于cocos2dx 3.2 cocos2dx 提供了一个基于xml的用户数据存贮类,给基于cocos2dx开发的用户数据存贮,这个类名就是UserDefault,在cocos2dx 2.x中是CCUserDefault。我的程序用的就是这个,但是最近老出错,于是分析源代码,发现了一个让我震惊的东西。经过分析,发现用UserDefault每读写一次数据,都会创建一个tinyxml对象,然后读取xml内容。如果是写数据,还是写入xml一次。下面是对应的代码: 读取key,所以各种读取key的操作,都是类似这样。 double UserDefault::getDoubleForKey(const char* pKey, double defaultValue) { const char* value = nullptr; tinyxml2::XMLElement* rootNode; tinyxml2::XMLDocument* doc; tinyxml2::XMLElement* node; node = getXMLNodeForKey(pKey, &rootNode, &doc); // find the node if (node && node->FirstChild()) { value = (const char*)(node->FirstChild()->Value()); }
double ret = defaultValue;
if (value) { ret = utils::atof(value); }
if (doc) delete doc;
return ret; } 关于getXMLNodeForKey的实现 /** * define the functions here because we don't want to * export xmlNodePtr and other types in "CCUserDefault.h" */
static tinyxml2::XMLElement* getXMLNodeForKey(const char* pKey, tinyxml2::XMLElement** rootNode, tinyxml2::XMLDocument **doc) { tinyxml2::XMLElement* curNode = nullptr;
// check the key value if (! pKey) { return nullptr; }
do { tinyxml2::XMLDocument* xmlDoc = new tinyxml2::XMLDocument(); *doc = xmlDoc;
std::string xmlBuffer = FileUtils::getInstance()->getStringFromFile(UserDefault::getInstance()->getXMLFilePath());
if (xmlBuffer.empty()) { CCLOG("can not read xml file"); break; } xmlDoc->Parse(xmlBuffer.c_str(), xmlBuffer.size());
// get root node *rootNode = xmlDoc->RootElement(); if (nullptr == *rootNode) { CCLOG("read root node error"); break; } // find the node curNode = (*rootNode)->FirstChildElement(); while (nullptr != curNode) { const char* nodeName = curNode->Value(); if (!strcmp(nodeName, pKey)) { break; }
curNode = curNode->NextSiblingElement(); } } while (0);
return curNode; } 关于setValueForKey的实现 static void setValueForKey(const char* pKey, const char* pValue) { tinyxml2::XMLElement* rootNode; tinyxml2::XMLDocument* doc; tinyxml2::XMLElement* node; // check the params if (! pKey || ! pValue) { return; } // find the node node = getXMLNodeForKey(pKey, &rootNode, &doc); // if node exist, change the content if (node) { if (node->FirstChild()) { node->FirstChild()->SetValue(pValue); } else { tinyxml2::XMLText* content = doc->NewText(pValue); node->LinkEndChild(content); } } else { if (rootNode) { tinyxml2::XMLElement* tmpNode = doc->NewElement(pKey);//new tinyxml2::XMLElement(pKey); rootNode->LinkEndChild(tmpNode); tinyxml2::XMLText* content = doc->NewText(pValue);//new tinyxml2::XMLText(pValue); tmpNode->LinkEndChild(content); } }
// save file and free doc if (doc) { doc->SaveFile(UserDefault::getInstance()->getXMLFilePath().c_str()); delete doc; } } 它的flush方法也有惊人的发现: void UserDefault::flush() { } 它是一个空函数,也就是说,你在写入数据的时候,会以为最后会通过flush才会写入数据,没想全错了! 如果你用它存贮比较多的字段时,你就会现,你悲剧了。 幸好发现及时,这里不建议大家使用UserDefault做为你的数据存贮。 可以可以用自定义的方式文件读写 如可以通过标准的C读写 fopen,fwrite等或iostream也都可以,重点是读写的文件路径,会有所不同,下面是得到文件路径的例子 std::string strFullFileName = FileUtils::getInstance()->getWritablePath() + DATA_FILE_NAME;
最后:不要求写太高质量的代码,但也不要写的太低质量了
本文地址:http://www.cppblog.com/zdhsoft/archive/2014/08/23/208104.html 经过几天的填坑,终于将现有的项目由cocos2dx 2.2.2移到cocos2dx 3.2,差点放弃3.2了,但在最后一刻,又把坑填平了。 cocos2dx 2.x到3.x是一个巨大的变化,可以算是完全不同。以前的类名,全是CC开头的,现在全部去掉了。很多enum都改用enum class了 所以,你知道2.x,对不起,你比小白学习3.x更难。你用2.x的做法用在3.x,那就全是坑了... 言归正传, 2.x的时候,按钮设置为Disabled的时候,是看不见。3.x的是没有禁用状态的,但是不会响应touch事件。 在cocostudio UI编辑的时候,按钮是三种状态的(有三个不同状态的图片),但没有相应改变状态的函数 于是,就分析源码,发现它是在onPressStateChangedToDisabled();更改为禁用状态的图片。再找,是于 在其基类的ui:Widget的setBright和setHighlight有调用这个onPressStateChangedToDisabled,但是setEnabled仅仅是改为了一个成员变化, 所以你在这里设置disabled,就不会有任何效果。除了上面两个函数之后,还有一个函数setBrightStyle是设置按钮是普通状态还是高亮状态 下面是BrightStyle的定义 enum class BrightStyle { NONE = -1, NORMAL, HIGHLIGHT }; 下面是一个包装的禁用启用的函数 //设置按钮禁用启用状态 inline void SetButtonEnabled(ui::Button * paramButton, bool paramEnabled) { if (isNULL(paramButton)) return; if (paramEnabled) { paramButton->setBright(true); paramButton->setEnabled(true); paramButton->setTouchEnabled(true); } else { paramButton->setBright(false); paramButton->setEnabled(false); paramButton->setTouchEnabled(false); } }
结果是:大家不要采用3.x系列的cocos2dx,还是用2.2.x吧 原因如下: 1、坑非常多,多的让你放弃 2、兼容性非常不好,如果你是2.x的工程,还是用2.x的吧 3、资料非常少,开发方提供了3.x版本,但是3.x的版本各项资料都非常欠缺!论坛上各种3.x的问题贴子,很多都没人回答。 4、3.x做了很多无所谓的精减,结果是,你用到这些他们精减的库时,你只有去哭了。(你的开发环境不可能和他们的一样,他们没问题,你的一定会有问题) 5、千万不要拿来3.x做商业化的程序,会大大增加你的开发周期和成本。
本文地址: http://www.cppblog.com/zdhsoft/archive/2014/08/04/207906.html今天,有空翻了一下<C++Primer plus(第六版)>,看到里面有介绍新的for循环和初始化列表,但是我实现的动态数组XDynamicArray不支持这些新特性,没办法,只好进行改造了。 首先是for循环,如下面的样式 for(auto e:stList) { cout<<e<<endl; } 是于就各种google,和查找C++11的array的源代码,总结:就是提供一个标准的iterator和begin,end这两个方法,就可以了。 是于定义了一个iterator //一个数组的Array的Iterator类 /* 这里提供XArrayIterator这个类,目的是使得这里支持C++11的for循环 */ template<class Array> class XArrayIterator { public: typedef typename Array::ElementType & reference; typedef typename Array::ElementType * pointer;
XArrayIterator() :m_Index(ARRAY_INVALID_INDEX), m_Array(nullptr) {}
XArrayIterator(Array * paramArray, XInt paramIndex) :m_Index(paramIndex), m_Array(paramArray) {}
XArrayIterator(Array & paramArray, XInt paramIndex) :m_Index(paramIndex), m_Array(¶mArray) {}
XArrayIterator(const XArrayIterator<Array> & paramR) :m_Index(paramR.m_Index), m_Array(paramR.m_Array) {}
XArrayIterator & operator = (const XArrayIterator<Array> & paramR) { if (this != ¶mR) { m_Index = paramR.m_Index; m_Array = paramR.m_Array; } return *this; }
XArrayIterator & operator = (Array * paramArray) { m_Array = paramArray; if (isNotNULL(m_Array)) { m_Array = m_Array->getFirstIndex(); } else { m_Index = ARRAY_INVALID_INDEX; } return *this; }
bool operator == (const XArrayIterator<Array> & paramR) { return m_Index == paramR.m_Index && m_Array == paramR.m_Array; }
bool operator != (const XArrayIterator<Array> & paramR) { return m_Index != paramR.m_Index || m_Array != paramR.m_Array; } reference operator*() { return (*m_Array)[m_Index]; } const reference operator*() const { return (*m_Array)[m_Index]; }
pointer operator->() { return &(*m_Array[m_Index]); }
const pointer operator->() const { return &(*m_Array[m_Index]); }
XArrayIterator & operator ++() { if (m_Index != ARRAY_INVALID_INDEX && isNotNULL(m_Array)) { m_Index++; if (m_Index >= m_Array->getLength()) m_Index = ARRAY_INVALID_INDEX; } return *this; }
XArrayIterator operator ++(int) { XArrayIterator stRet = *this; if (m_Index != ARRAY_INVALID_INDEX && isNotNULL(m_Array)) { m_Index++; if (m_Index >= m_Array->getLength()) m_Index = ARRAY_INVALID_INDEX; } return stRet; }
XArrayIterator & operator --() { if (m_Index != ARRAY_INVALID_INDEX && isNotNULL(m_Array)) { m_Index--; if (m_Index < 0) m_Index = ARRAY_INVALID_INDEX; } return *this; }
XArrayIterator operator --(int) { XArrayIterator stRet = *this; if (m_Index != ARRAY_INVALID_INDEX && isNotNULL(m_Array)) { m_Index--; if (m_Index < 0) m_Index = ARRAY_INVALID_INDEX; } return stRet; }
XArrayIterator & operator +=(XInt paramOffset) { if (m_Index != ARRAY_INVALID_INDEX && isNotNULL(m_Array)) { m_Index += paramOffset; if (!(m_Index >= 0 && m_Index < m_Array->getLength())) { m_Index = ARRAY_INVALID_INDEX; } } return *this; }
XArrayIterator operator + (XInt paramOffset) const { XArrayIterator stRet = *this; stRet += paramOffset; return stRet; }
XArrayIterator & operator -=(XInt paramOffset) { return operator += (-paramOffset); }
XArrayIterator operator - (XInt paramOffset) const { XArrayIterator stRet = *this; stRet -= paramOffset; return stRet; } private: XInt m_Index; Array * m_Array; }; 然后在XDynamicArray两个方法 typedef XArrayIterator<XDynamicArray<T> > iterator /*这里定义begin和end主要有两个目的 目的1:使它可以像标准STD容器那样遍历 目的2:使它可以支持C++11的for循环 例子: XDynamicArray<int> st; for(auto x:st) { cout<<x<<endl; } */ iterator begin() { iterator stRet(this, this->getFirstIndex()); return stRet; }
iterator end() { iterator stRet(this, ARRAY_INVALID_INDEX); return stRet; } 这样就可以了,测试通过。你们也可以试试。 C++11的另一个特性,就是新初始化列表,如下面例子 vector st {1,2,3,4,5}; 看起来有点意思,于是又google一下,翻阅了各位大神的贴子,最终找到,然后我就实现了。这部分需要使用C++11的initializer_list模板类,具体使用代码如下。 //这个构造函数的定义,是为了实现C++11的初始化列表,如下例子 /* XDynamicArray<int> st {1,2,3,4,5}; 或 XDynamicArray<int> st = {1,2,3,4,5}; */ XDynamicArray(std::initializer_list<T> paramList) : m_Length(0), m_Capacity(0), m_Data(NULL) { this->ensureCapacity((XInt)paramList.size()); for (auto e : paramList) { Append(e); } } 使用initializer_list需要头文件:#include <initializer_list> 上述代码,已经放到我的开放库中了,大家可以自行下载。 我的开放代码
本文地址: http://www.cppblog.com/zdhsoft/archive/2014/08/01/207880.html现在C++智能指针有无数个实现了,多一个也无所谓。哈。 这个智能指针是专门为cocos2dx 2.2.x定制的。主要是为了方便使用,同时又要遵循现有的cocos2dx的内存管理。特实现这样一个智能指针。在使用的时候不需要考虑retain或release操作,也不需要new或delete操作! 下面是实现代码 //在很多时候,类的成员是CCObject的子对象,为了保证对其正常使用,又要遵循cocos2dx的内存管理,特实现了这样的一个智能指针,方便使用。 #ifndef _X_COCOS_PTR_H_ #define _X_COCOS_PTR_H_ namespace zdh { template<class T> class XCocosPtr { public: XCocosPtr() :m_Object(nullptr) {}
XCocosPtr(T * paramObject) :m_Object(paramObject) { if (m_Object != nullptr) { m_Object->retain(); } }
XCocosPtr(const XCocosPtr & paramPtr) :m_Object(paramPtr.m_Object) { if (m_Object != nullptr) { m_Object->retain(); } }
~XCocosPtr() { ptr_release(); } //重载赋值运算符 XCocosPtr & operator = (T * paramObject) { set(paramObject); return *this; }
XCocosPtr & operator = (XCocosPtr & paramObject) { set(paramObject.m_Object); return *this; } //重载比较运算符 bool operator == (T * paramObject) const { return m_Object == paramObject; }
bool operator != (T * paramObject) const { return m_Object != paramObject; } //重载*运算符 T & operator*() { return *m_Object; }
const T & operator*() const { return *m_Object; } //重载->运算符,使其可以像指针那样使用 T * operator ->() { return m_Object; }
const T * operator ->() const { return m_Object; } //判断对象是否为空 bool is_null() const { return m_Object == nullptr; } //判断对象是否为不空 bool is_not_null() const { return m_Object != nullptr; } //创建对象 这里会使用调用对象的create来创建对象 T * create() { T * pNewObject = T::create(); set(pNewObject); return pNewObject; } //设置对象 void set(T * paramObject) { if (m_Object != paramObject) { T * p = m_Object; m_Object = paramObject; if (m_Object != nullptr) { m_Object->retain(); } if (isNotNULL(p)) { p->release(); } } } //取对象 T * get() { return m_Object; } //这里没有使用release这个名称,是为了防止和object的release混淆 void ptr_release() { if (m_Object != nullptr) { m_Object->release(); m_Object = nullptr; } } private: T * m_Object; }; } #endif 例子 //类的数据成员定义:
XCocosPtr<CCSprite> m_Sprite; //在init中
m_Sprite = CCSprite::create(" "); //或
m_Sprite.create()
本文地址: http://www.cppblog.com/zdhsoft/archive/2014/07/25/207805.html用CCLabelTTF显示的数字不好看,于是就想到用图片来代理。目前网上的实现都是把每个数字做一个CCSprite组合的方式。但是我想,动态生成纹理的方式。没有就只好自己手动写一个。 头文件 #ifndef _X_NUMBER_H_ #define _X_NUMBER_H_ #include <cocos2d.h> #include <xtype.h> namespace cocos2d { //基于图片显示的数字 /* 这个类不是用一个一个数字拼起来,而是渲染成一个独立的纹理 zdh::XDDWord是一个64位无符号整数 */ class CCPictureNumber : public CCSprite { public: typedef CCSprite Inherited; public: CCPictureNumber(); ~CCPictureNumber(); virtual bool init(void); int BuildNumber(zdh::XDDWord paramNumber, const char * paramNumberResName); int BuildNumber(zdh::XDDWord paramNumber, CCTexture2D * paramTexture); int BuildNumber(zdh::XDDWord paramNumber); CREATE_FUNC(CCPictureNumber);
void setNumberTexture(CCTexture2D * paramTexture); void setNumberTexture(const char * paramNumberResName); CCTexture2D * getNumberTexture();
zdh::XDDWord getNumber() const; void setNumber(zdh::XDDWord paramNumber); int Build(); private: CCTexture2D * m_NumberTexture; zdh::XDDWord m_Number; }; } #endif 源文件 #include "xpicture_number.h" #include <xstring.h> namespace cocos2d { //-------------------------------------------------------------------------------------- //从指定资源名称构建 int CCPictureNumber::BuildNumber(zdh::XDDWord paramNumber, const char * paramNumberResName) { this->setNumber(paramNumber); this->setNumberTexture(CCTextureCache::sharedTextureCache()->addImage(paramNumberResName)); return this->Build(); }
//-------------------------------------------------------------------------------------- //从指定纹理构建 int CCPictureNumber::BuildNumber(zdh::XDDWord paramNumber, CCTexture2D * paramTexture) { this->setNumber(paramNumber); this->setNumberTexture(paramTexture); return this->Build(); } //-------------------------------------------------------------------------------------- int CCPictureNumber::BuildNumber(zdh::XDDWord paramNumber) { this->setNumber(paramNumber); return this->Build(); }
//-------------------------------------------------------------------------------------- bool CCPictureNumber::init(void) { if (!Inherited::init()) return false; return true; } //-------------------------------------------------------------------------------------- CCPictureNumber::CCPictureNumber() { m_NumberTexture = nullptr; m_Number = 0; } //-------------------------------------------------------------------------------------- CCPictureNumber::~CCPictureNumber() { if (zdh::isNotNULL(m_NumberTexture)) { m_NumberTexture->release(); } } //-------------------------------------------------------------------------------------- void CCPictureNumber::setNumberTexture(CCTexture2D * paramTexture) { if (m_NumberTexture == paramTexture) return; if (zdh::isNotNULL(m_NumberTexture)) { m_NumberTexture->release(); } m_NumberTexture = paramTexture; if (zdh::isNotNULL(m_NumberTexture)) { m_NumberTexture->retain(); } } //-------------------------------------------------------------------------------------- void CCPictureNumber::setNumberTexture(const char * paramNumberResName) { this->setNumberTexture(CCTextureCache::sharedTextureCache()->addImage(paramNumberResName)); }
//-------------------------------------------------------------------------------------- CCTexture2D * CCPictureNumber::getNumberTexture() { return m_NumberTexture; } //-------------------------------------------------------------------------------------- int CCPictureNumber::Build() { if (zdh::isNULL(m_NumberTexture)) return zdh::ERR_FAIL;
zdh::XAnsiString strNumber(m_Number); //将整数转换为字符串 int iNumCount = strNumber.getLength(); //取得字符个数 CCSize stSize = m_NumberTexture->getContentSize(); //取得纹理大小,要求纹理中每个数字都是等宽等高,并依照0123456789排列 int iNumWidth = (int)stSize.width / 10; //纹理中每个数字的宽度 int iNumHeight = (int)stSize.height; //纹理中每个数字的高度
CCRenderTexture * pRT = CCRenderTexture::create(iNumWidth * iNumCount, iNumHeight); //创建渲染纹理对象,并数字确定宽度 CCSprite * pSprite = CCSprite::create(); //创建精灵对象,用于绘制数字 pSprite->setAnchorPoint(0, 0); pSprite->setTexture(m_NumberTexture); CCRect stRect; pRT->begin(); for (int i = 0; i < iNumCount; i++) { int iNumber = strNumber[i] - '0'; //设置要显示数字的纹理区域,这个区域是指参数中paramTexture中区域 stRect.setRect(iNumber * iNumWidth, 0, iNumWidth, iNumHeight); pSprite->setTextureRect(stRect, false, stRect.size); pSprite->setPosition(i * iNumWidth, 0); //计算显示的偏移位置 pSprite->visit(); //渲染到pRT中 } pRT->end(); //取得生成的纹理 this->setTexture(pRT->getSprite()->getTexture()); //设置显示的内容 stRect.setRect(0, 0, iNumWidth * iNumCount, iNumHeight); this->setTextureRect(stRect, false, stRect.size); //默认的情况下,通过CCRenderTexture得到的纹理是倒立的,这里需要做一下翻转 this->setFlipY(true); //释放资源 delete pSprite; delete pRT; return zdh::ERR_OK; } //-------------------------------------------------------------------------------------- zdh::XDDWord CCPictureNumber::getNumber() const { return m_Number; } //-------------------------------------------------------------------------------------- void CCPictureNumber::setNumber(zdh::XDDWord paramNumber) { m_Number = paramNumber; }
} 数字图片文件 使用例子 CCPictureNumber * pNum = CCPictureNumber::create(); pNum->BuildNumber(1234567, "ui_play_num05.png"); pNum->setPosition(200, 200); pNum->setAnchorPoint(0, 0);
this->addChild(pNum, 100); //
本文地址: http://www.cppblog.com/zdhsoft/archive/2014/07/23/207760.html使用cocostudio可以装载编辑好的UI,但是过于复杂。特别是在加截UI后,发现触屏事件有些问题。如果直接使用程序写死加载UI又过于麻烦。花点时间,增加了一个基于ini的UI配置类,目前只实现了CCSprite和plist的加载。其它的可以后面慢慢加 头文件 #ifndef _X_UI_H_ #define _X_UI_H_ #include <cocos2d.h> namespace zdh { USING_NS_CC; void CreateByXUI(CCNode * paramParent, const char * paramFileName); } #endif 源文件 #include "xui.h" #include "xini.h" #include "xlog.h"
namespace zdh { namespace xui { //-------------------------------------------------------------------------------------- int GetIntValue(XIniText::TSection * paramSection, const char * paramKeyName) { auto pV = paramSection->getEntry(paramKeyName); if (isNULL(pV)) return 0; else return pV->getValue().getField().ToIntDef(0); } //-------------------------------------------------------------------------------------- int GetDoubleValue(XIniText::TSection * paramSection, const char * paramKeyName) { auto pV = paramSection->getEntry(paramKeyName); if (isNULL(pV)) return 0; else return pV->getValue().getField().ToIntDef(0); } //-------------------------------------------------------------------------------------- const XAnsiString & GetStringValue(XIniText::TSection * paramSection, const char * paramKeyName) { static const XAnsiString strEmpty; auto pV = paramSection->getEntry(paramKeyName); if (isNULL(pV)) return strEmpty; else return pV->getValue().getField(); } };
//-------------------------------------------------------------------------------------- void CreateSpriteByXUI(CCNode * paramParent, XIniText::TSection * paramSpriteSection) { XInt ix = xui::GetIntValue(paramSpriteSection, "x"); XInt iy = xui::GetIntValue(paramSpriteSection, "y"); XInt izOrder = xui::GetIntValue(paramSpriteSection, "zOrder"); const XAnsiString & pImageName = xui::GetStringValue(paramSpriteSection, "image"); XInt iTag = xui::GetIntValue(paramSpriteSection, "tag"); CCSprite * pSprite = NULL; if (pImageName[0] == ':') //如果是从Cache中读取 { pSprite = CCSprite::createWithSpriteFrameName(pImageName.c_str()+1); } else { pSprite = CCSprite::create(pImageName.c_str()); } pSprite->setPosition(ix, iy); pSprite->setAnchorPoint(0, 0); pSprite->setTag(iTag); pSprite->setZOrder(izOrder); paramParent->addChild(pSprite, izOrder); } void LoadSpriteFrameByPList(CCNode * /*paramParent*/, XIniText::TSection * paramSection) { const XAnsiString & pPListName = xui::GetStringValue(paramSection, "filename"); CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(pPListName.c_str()); }
//-------------------------------------------------------------------------------------- void CreateByXUI(CCNode * paramParent, const char * paramFileName) { std::string strFullFileName = CCFileUtils::sharedFileUtils()->fullPathForFilename(paramFileName); unsigned long dwGetSize = 0; const unsigned char * pData = CCFileUtils::sharedFileUtils()->getFileData(strFullFileName.c_str(), "rb", &dwGetSize); ZDH_INFO("Load XUI:%s size=%u", paramFileName, dwGetSize); if (dwGetSize == 0) { if (isNotNULL(pData)) delete[] pData; return; }
std::string strData((const char *)pData, dwGetSize); std::stringstream ss(strData); XIniText stIni; if (!stIni.Load(ss)) { ZDH_INFO("Load XUI Fail, %s", paramFileName); return; } for (int s = 0; s < stIni.getSectionCount(); s++) { auto pSection = stIni.getSection(s); auto pType = pSection->getEntry("type"); if (isNULL(pType)) { ZDH_INFO("Section=[%s] not exist key:\"type\"", pSection->getSectionName().c_str()); continue; } const XAnsiString & paramTypeValue = pType->getValue().getField(); if (paramTypeValue == "CCSprite") { CreateSpriteByXUI(paramParent, pSection); } else if (paramTypeValue == "plist") { LoadSpriteFrameByPList(paramParent, pSection); } } } } 配置文件 #支持UTF-8格式 [gk_label.png] type = CCSprite image = gk_label.png tag = 1 x = 18 y = 914 zOrder = 1
[mb_label.png] type = CCSprite image = :mb_label.png ·#冒号开头表示从CCSpriteFrameCache加载图片 tag = 1 x = 348 y = 916 zOrder = 1
[score_label.png] type = CCSprite image = score_label.png tag = 1 x = 258 y = 855 zOrder = 1
[game_star.plist] #批量装载 type = plist filename = game_star.plist 相关用到的TTextIni和XAnsiString,参考 我的开源代码
本文地址: http://www.cppblog.com/zdhsoft/archive/2014/07/23/207756.html这四个是我用的主要IDE。 VS+Visual AssistX可以用无敌开形容,太强大了。虽然我只用来写C++代码。我个人觉得,应该没有什么IDE可以超过它的。没有什么好形容它的,就是一直在用它... Eclipse也是一个非常强的,除了java,它还可以是C++,lua,tcl,python,ActionScript3等语言的IDE,现在cocos2dx也基于它推出cocos2dx 3.x系列的lua语言IDE。最新版本是luna,但是这次感觉和以前有一个最大的变化就是Menu->Help->Install new software,以前你要装C++,那需要到CDT的页面找插件的更新地址,其它语言也是类似。但是这次它提供一个luna的插件链接,可以安装各种你想要的eclipse插件,不用再一个一个找了。 当然,一些不是eclipse一起开发的,就还是要用老方法了。在eclipse这个工具,又衍生出FlashBuilder和ADT这两个目前比较常见的开发工具,一个用于开发Flash,一个用于开发Android。虽然它很NB,但是我也只是拿它打打酱油。另然,eclipse的工程文件,是让我非常无语的地方,比起vs等IDE,复杂多了。它的重构功能,还不够,这是两点是我拿它打酱油的原因。 C++Builder是我曾经用过的编辑器,它曾经是非常牛的。用它开发数据库和windows应用,一个字,就是快。兼顾速度和可视开发以及C++,虽然比它的本尊delphi差些,也比那个时候的vc强很多,易用性不比vb差。C++Builder6最后一个值得怀念的,后面borland把它的根本开发工具卖了。最近最新的RAD Studio XE6也发布了,可以可视化开发Android和windows以及iOS应用,可惜bug太多,当玩具可以,不怕死的,可以拿它去开发商业软件。如果你没买正版,它们的代理会来找你麻烦。还有它的安装文件巨大,你的C盘没20G,就不要去试了。borland为什么会死,就是自己作死的。还有不得不提一下Turbo C 2.0,这是我用过最好的IDE之一,非常经典。(Borland Turbo C,Turbo Pascal,Borland C++ 3.1,等都是经典) JCreator是我当用java语言开发的时候,用到的。我用它的原因是,它非常小,非常干净,比eclipse用起来清爽多了。可惜它发展的不怎么样。 除了上面4个,我还常用editplus,notepad++和vi等编辑器。nodepad重点在语言加亮,editplus在于它非常小巧,功能强大,非常清爽,是我开发必备的工具。因为要常在linux下修改数据,所以vi也是常用之一,可惜只用它皮毛。 现在vs的版本是2013,从2012提供了python插件。python开发者们有福了。
|