首页 > 代码库 > cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第四步---编辑器(3)--坐标保存&加载文件操作
cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第四步---编辑器(3)--坐标保存&加载文件操作
/* 说明:
**1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记
**2.我也问过木头本人啦,他说:随便写,第一别完全照搬代码;第二可以说明是学习笔记---好人
**3.这里用cocos2d-x 3.0版本重写,很多地方不同,但是从重写过程中也很好的学习了cocos2d-x
*/
***每一步对应的所有代码以及用到的资源都会打包在最后给出
***为避免代码过多,每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)
***可以根据设计思路(好吧,那名字太高大上。实际就是这一步要干啥)先自己实现---cocos2d-x本来就是如此,相同的功能有许多不同实现方法;先自己折腾是蛮不错的。
***为了方便移植到手机上,对于每一步都进行编译android测试;因为很多时候代码在win32下可以,编译就会出错,给出的代码会是测试过后的。
本次笔记内容:
1、稍微分析
2、看代码
3、下次内容预览
4、代码&资源下载
5、这里主要是文件操作;到这里编辑器部分也结束啦。后面就是游戏过程的设计啦
效果图---没啥效果,文件操作又看不出什么
那么到这里,先将代码分类下:
一:分析
1、我们可以先处理编辑不同关卡的实现,每次nextLvl的时候,将本层清空,重新加载地图
2、然后就是与文件挂钩,对于TowerPos和MonsterPos我们有对应容器保存;但是我们需要保存到文件中,为后面游戏加载做准备
二:代码
先处理简单的,编辑不同级别的关卡,添加 deleteAllPos函数,以及修改改变关卡的函数:
这里对于切换关卡实际上就是编辑层清空,重新加载其他关卡地图,进行编辑---(好吧,这里由于只有三个地图,就限制三个关卡,而且地图都是一样的.......)
void TowerPosEditorLayer::deleteAllPos(){ this->removeAllChildrenWithCleanup(true); m_monsterPosList.clear(); m_towerPosList.clear(); } void TowerPosEditorLayer::nextLvl(){ if(m_iCurLevel == 3){ return ; } deleteAllPos(); m_iCurLevel ++; loadConfigFile(); } void TowerPosEditorLayer::preLvl(){ if(m_iCurLevel == 1){ return; } deleteAllPos(); m_iCurLevel --; loadConfigFile(); }到这也可以进行测试
------------------------------------------------------------------------------------
但是编辑过的地图怎么能不保存;而且,假若我编辑了第一关之后,保存,然后到第二关之后,我觉得第一关有一点点需要修改怎么办?
那么这里用一个坐标的文件操作 PosLoadUtil
这里又两个功能,加载已有的,和 把已有的输出到文件
需要小小的总结的是这是一个单例类,粗糙的了解一下单例类:
比如你拍一部电影,今天在北京有一个场戏,明天去上海由一场戏;那么这里看做是两个场景,不同的场景,你导演总不会变:Director 应该就是一个单例类(我是这么理解的)
那么我们自己来弄一个单例类:独家供应饭店;首先是没有的,我们就create一个 ,它是static 的也就是存在整个电影的拍摄过程;随便你去哪里,打个电话::getInstence()--->送饭啦;就OK
上马:.h
class PosLoadUtil : public Node{ public: static PosLoadUtil* getInstance(); virtual bool init(); //**4** void putToFile(Vector<PosBase*> posList, const char* sFilePath); //**4**选择传Vector<PosBase*>类型的引用 void loadPosWithFile(Vector<PosBase*>& List, EnumPosType posType, const char* sFilePath, Node* container, int level, bool isDebug); private: static PosLoadUtil* _posLoadUtil; };。cpp
#include "PosLoadUtil.h" PosLoadUtil* PosLoadUtil::_posLoadUtil = NULL; PosLoadUtil* PosLoadUtil::getInstance(){ if(_posLoadUtil == NULL){ _posLoadUtil = new PosLoadUtil(); if(_posLoadUtil && _posLoadUtil->init()){ _posLoadUtil->autorelease(); }else{ CC_SAFE_DELETE(_posLoadUtil); } } return _posLoadUtil; } bool PosLoadUtil::init(){ return true; } void PosLoadUtil::putToFile(Vector<PosBase*> posList, const char* sFilePath){ FILE* file = fopen(sFilePath, "w"); // xml头部信息 fprintf(file,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); fprintf(file,"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"); // plist父节点字段开头 fprintf(file,"<plist version=\"1.0\">\n"); // <array> fprintf(file,"<array>\n"); // 各个属性 PosBase* posBase = NULL; for(auto ref : posList) { posBase = dynamic_cast<PosBase*>(ref); if(posBase != NULL) { // <dict> fprintf(file," <dict>\n"); // <key>x</key> fprintf(file," <key>x</key>\n"); // <integer>80</integer> fprintf(file," <integer>%.0f</integer>\n", posBase->getPos().x); // <key>y</key> fprintf(file," <key>y</key>\n"); // <integer>266</integer> fprintf(file," <integer>%.0f</integer>\n", posBase->getPos().y); // </dict> fprintf(file," </dict>\n"); } } // </array> fprintf(file,"</array>\n"); // plist父节点字段结束 fprintf(file,"</plist>\n"); fclose(file); } void PosLoadUtil::loadPosWithFile(Vector<PosBase*>& List, EnumPosType posType, const char* sFilePath, Node* container, int iLevel, bool isDebug ) { // 读取plist文件 auto value_Vector = FileUtils::getInstance()->getValueVectorFromFile(sFilePath); for(auto ref : value_Vector) { //将value_Vector 里面读取的对象ref 转化为ValueMap 类型 auto temp_map = ref.asValueMap(); //转化之后的ValueMap 对象 temp_map 取出x,y值 auto x = temp_map.at("x").asFloat(); auto y = temp_map.at("y").asFloat(); PosBase* posBase = PosBase::create(ccp(x,y), posType, isDebug); List.pushBack(posBase); container->addChild(posBase,iLevel); } }然后,在PosEditorLayer中的文件输出函数中修改:
void PosEditorLayer::outputPosToPlistFile(){ CCLOG("outputPosToPlistFile"); // 输出炮台坐标配置文件 __String* sTowerPosPath = __String::createWithFormat("game/towerPos_level_%d.plist", _curLevel); PosLoadUtil::getInstance()->putToFile(m_towerPosList,sTowerPosPath->getCString()); // 输出怪物坐标配置文件 __String* sMonsterPosPath = __String::createWithFormat("game/monsterPos_level_%d.plist", _curLevel); PosLoadUtil::getInstance()->putToFile(m_monsterPosList,sMonsterPosPath->getCString()); }在PosEditorLayer的preLoad函数中:
void PosEditorLayer::preLoad(){ /*******省略代码*********************** //加载TowerPos __String* sTowerPosPath =__String::createWithFormat("game/towerPos_level_%d.plist",_curLevel); PosLoadUtil::getInstance()->loadPosWithFile(m_towerPosList, enTowerPos, sTowerPosPath->getCString(), this,10,true); /**/ //加载MonsterPos __String* sMonsterPosPath = __String::createWithFormat("game/monsterPos_level_%d.plist", _curLevel); PosLoadUtil::getInstance()->loadPosWithFile(m_monsterPosList, enMonsterPos, sMonsterPosPath->getCString(), this,10,true); }好吧,可以欢乐的测试啦,相应目录下也可以看到对应文件
当然,就算你最开始的目录下没有对应文件,你加载也不会出问题
小小的注意一下:这里怪物的路线点,得按顺序编辑之后再保存,不然后面怪物走的时候,是按照点的顺序走的。。。会乱走
三:下次内容预览
编辑了你想要的地图之后;开始了正式的游戏Scene;炮台的坐标点加载之后肯定在点的位置是要放置炮台的。。
----------------------------------------
四:源码&资源
-----------------------------------------
个人愚昧观点,欢迎指正与讨论
cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第四步---编辑器(3)--坐标保存&加载文件操作