首页 > 代码库 > cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第七步---英雄要升级&属性--解析csv配置文件

cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第七步---英雄要升级&属性--解析csv配置文件

/* 说明:

**1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记

**2.我也问过木头本人啦,他说:随便写,第一别完全照搬代码;第二可以说明是学习笔记---好人大笑

**3.这里用cocos2d-x 3.0版本重写,很多地方不同,但是从重写过程中也很好的学习了cocos2d-x

*/

***每一步对应的所有代码以及用到的资源都会打包在最后给出

***为避免代码过多,每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)

***可以根据设计思路(好吧,那名字太高大上。实际就是这一步要干啥)先自己实现---cocos2d-x本来就是如此,相同的功能有许多不同实现方法;先自己折腾是蛮不错的。

***为了方便移植到手机上,对于每一步都进行编译android测试;因为很多时候代码在win32下可以,编译就会出错,给出的代码会是测试过后的。

本次笔记内容:

1、设计思路

2、思路代码&效果图

3、下次内容预览

4、本次资源&完整代码下载

一:设计思路

1.首先英雄升级体现放置Hero里面upgrade函数,对应升级有不同的效果体现

2.升级操作抽离成一个操作器继承自Node,然后绑定在炮台上,后面点击炮台,出现三个按钮---升级、关闭、删除英雄

3.英雄的升级不只是体现在外表,它也有属性,属性提升---属性就得从csv文件读取

5.由于这后面思路基本借鉴书上的,就不班门弄斧啦---直接在代码中结束

二:思路代码&效果图

首先给英雄升级函数;这里写得比较死,同时只支持4级提升;每一次提升之后就弄一个动作覆盖上去

 

[cpp] view plaincopy
  1. void Hero::upgrade(){  
  2.     Sprite* sprite = getSprite();  
  3.     if(sprite == NULL || _level >= 4) {  
  4.         return;  
  5.     }  
  6.   
  7.     // 增加等级   
  8.     _level++;  
  9.   
  10.     // 英雄遮罩   
  11.     if(_level == 2) {  
  12.         Sprite* heroTop = Sprite::create("sprite/hero/hero_top_1.png");  
  13.         Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2);  
  14.         heroTop->setPosition(pos);  
  15.         sprite->addChild(heroTop);  
  16.     }  
  17.     if(_level == 3) {  
  18.         Sprite* heroTop = Sprite::create("sprite/hero/hero_top_2.png");  
  19.         heroTop->setOpacity(255);  
  20.         Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2);  
  21.         heroTop->setPosition(pos);  
  22.         sprite->addChild(heroTop);  
  23.   
  24.         ActionInterval* rotateBy = RotateBy::create(25.0f, 360, 360);  
  25.         ActionInterval* repeat = RepeatForever::create(rotateBy);  
  26.         heroTop->runAction(repeat);  
  27.     }  
  28.     if(_level == 4) {  
  29.         Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2);  
  30.         Sprite* heroTop = Sprite::create("sprite/hero/hero_top_3.png");  
  31.         heroTop->setPosition(pos);  
  32.         sprite->addChild(heroTop);  
  33.   
  34.         ActionInterval* rotateBy = RotateBy::create(10.0f, 360, 360);  
  35.         ActionInterval* repeat = RepeatForever::create(rotateBy);  
  36.         heroTop->runAction(repeat);  
  37.     }  
  38.   
  39. }  

那么对应四个基本的不同效果如下:

lv1----lv2----lv3------lv4

效果是动态的动作

--------------------------------------------------------------

那么看看那操作器 TowerOperator;它需要和Hero以及炮台保存联系,需要这两个成员

 

[cpp] view plaincopy
  1. class TowerOperator : public Node{  
  2. public:  
  3.     TowerOperator();  
  4.     ~TowerOperator();  
  5.     static TowerOperator* create(TowerBorder* towerBorder,Hero* hero);  
  6.     bool init(TowerBorder* towerBorder,Hero* hero);  
  7.   
  8. private:  
  9.     Hero* _hero;  
  10.     TowerBorder* _towerBorder;  
  11.   
  12.     void createOprBtns();  
  13.   
  14.     //**7**按钮事件  
  15.     void closeEvent(Ref* pSender,Control::EventType event);  
  16.     void upgradeEvent(Ref* pSender,Control::EventType event);  
  17.     void deleteEvent(Ref* pSender,Control::EventType event);  
  18. };  

实现

 

[cpp] view plaincopy
  1. TowerOperator::TowerOperator(){  
  2.     _hero = NULL;  
  3.     _towerBorder = NULL;  
  4. }  
  5. TowerOperator::~TowerOperator(){  
  6.     CC_SAFE_RELEASE(_hero);  
  7.     CC_SAFE_RELEASE(_towerBorder);  
  8. }  
  9.   
  10. TowerOperator* TowerOperator::create(TowerBorder* towerBorder,Hero* hero){  
  11.     TowerOperator* towerOperator = new TowerOperator();  
  12.     if(towerOperator && towerOperator->init(towerBorder,hero)){  
  13.         towerOperator->autorelease();  
  14.     }  
  15.     else{  
  16.         CC_SAFE_DELETE(towerOperator);  
  17.     }  
  18.     return towerOperator;  
  19. }  
  20.   
  21. bool TowerOperator::init(TowerBorder* towerBorder, Hero* hero){  
  22.     CC_SAFE_RETAIN(towerBorder);  
  23.     _towerBorder = towerBorder;  
  24.   
  25.     CC_SAFE_RETAIN(hero);  
  26.     _hero = hero;  
  27.   
  28.     createOprBtns();  
  29.     return true;  
  30. }  
  31.   
  32. void TowerOperator::createOprBtns(){  
  33.     LabelTTF* title = LabelTTF::create("Close", "Arial", 25);  
  34.   
  35.     auto m_pos = this->getPosition();  
  36.   
  37.     ControlButton* closeBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png"));  
  38.     closeBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED);  
  39.     closeBtn->addTargetWithActionForControlEvents(this,  
  40.         cccontrol_selector(TowerOperator::closeEvent), Control::EventType::TOUCH_UP_INSIDE);  
  41.     closeBtn->setPosition(  
  42.         ccp(m_pos.x+100,m_pos.y));  
  43.     this->addChild(closeBtn);  
  44.       
  45.     title = CCLabelTTF::create("Delete", "Arial", 25);  
  46.     ControlButton* deleteBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png"));  
  47.     deleteBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED);  
  48.     deleteBtn->addTargetWithActionForControlEvents(this,   
  49.         cccontrol_selector(TowerOperator::deleteEvent), Control::EventType::TOUCH_UP_INSIDE);  
  50.     deleteBtn->setPosition(  
  51.         ccp(m_pos.x-100,m_pos.y));  
  52.     this->addChild(deleteBtn);  
  53.   
  54.     title = CCLabelTTF::create("Upgrade",  "Arial", 25);  
  55.     ControlButton* upgradeBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png"));  
  56.     upgradeBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED);  
  57.     upgradeBtn->addTargetWithActionForControlEvents(this,   
  58.         cccontrol_selector(TowerOperator::upgradeEvent), Control::EventType::TOUCH_UP_INSIDE);  
  59.     upgradeBtn->setPosition(  
  60.         ccp(m_pos.x,m_pos.y+100));  
  61.     this->addChild(upgradeBtn);  
  62. }  
  63.   
  64. void TowerOperator::closeEvent(Ref* pSender,Control::EventType event){  
  65.     CCLOG("close!");  
  66.     this->removeFromParentAndCleanup(true);  
  67. }  
  68. void TowerOperator::upgradeEvent(Ref* pSender,Control::EventType event){  
  69.     CCLOG("upgrade!");  
  70.     _hero->upgrade();  
  71. }  
  72. void TowerOperator::deleteEvent(Ref* pSender,Control::EventType event){  
  73.     CCLOG("delete!");  
  74.     _towerBorder->deleteHero();  
  75.     this->removeFromParentAndCleanup(true);  
  76. }  

三个按钮,这里也要注意的是相对位置的放置问题,也就是son & parent的位置问题

三个按钮的函数比较简单,那么对应删除操作,是由——_towerBorder去完成的,其函数为:

 

[cpp] view plaincopy
  1. void TowerBorder::deleteHero(){  
  2.     _hero->removeFromParentAndCleanup(true);  
  3.     CC_SAFE_RELEASE_NULL(_hero);  
  4. }  

并且,要注意,不要用_hero直接从parent删除,不然导致这个炮台下次无法继续添加

那么我们的操作器得展示出来;回想往炮台加英雄的时候,是在触摸事件中,次炮台没有英雄的时候就添加,那么如果有,我们就显示操作器就是啦:

 

[cpp] view plaincopy
  1. void TowerBorder::showOperator(){  
  2.     auto towerOperator = TowerOperator::create(this,_hero);  
  3.     CC_SAFE_RETAIN(towerOperator);  
  4.     towerOperator->setPosition(ccp(0,0));  
  5.     this->addChild(towerOperator);  
  6. }  
  7. //这里的setPostion以及操作器里面的setPos也和前面说过的相对位置有关  
  8. bool HeroManager::initWithLevel(int curLevel){  
  9.     /********************省略*****************/  
  10.     listener->onTouchEnded = [=](Touch* touch,Event* event){  
  11.             /********************省略*****************/  
  12.         if(clickBorder->getHero() == NULL){  
  13.             Hero* hero = Hero::createFromCsvFileByID(1);  
  14.             hero->setPosition(clickBorder->getPosition());  
  15.             this->addChild(hero);  
  16.             clickBorder->bindHero(hero);  
  17.         }  
  18.         else{  
  19.             clickBorder->showOperator();  
  20.         }  
  21.     };  
  22.   
  23.     _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);  
  24.   
  25.     //------------------------------------------------------------  
  26.   
  27.     return true;  
  28. }  

效果如下:

那么,我们英雄的升级有了外表的体现啦

可是我们的英雄一直没有属性上的配置-----------------这要通过csv 来弄;

首先需要说明的是:

csv是一种简单的文件,你可以用Excel 来弄,外观像表格,最后保存的格式为csv就是的。但是用记事本打开,就会发现实际上是用逗号分隔开的如图:

----------------------

那么这里的csv需要解析,然后放到我们的cocos2d-x 里面,使用这些属性;

具体的也是木头书上的,我这里不过多说;但是在3.0版本中,也修改了不少地方。同时为了移植到手机上,也做了相应的修改;这里解析csv文件有三个类:

FileLoadUtil---文件加载  、StringUtil---字符串解析 、CsvUtil---由前两个配合完成最终解析;如果相应了解其具体工作,最好的方式就是一步步调试,那样很容易理解

---------------------------------------------------------------------------------------------------------------

那么看看那英雄的属性  Hero.h里面:

 

[cpp] view plaincopy
  1. enum EnumHeroType{  
  2.     en_HeroType_Normal  
  3. };  
  4. enum EnumHeroPropConfType{  
  5.     enHeroPropConf_ID,      // 英雄ID  
  6.     enHeroPropConf_Name,        // 英雄名字  
  7.     enHeroPropConf_Type,        // 英雄类型  
  8.     enHeroPropConf_ModelID,     // 英雄模型ID  
  9.     enHeroPropConf_BaseAtk,         // 基础攻击力  
  10.     enHeroPropConf_AtkSpeed,        // 攻击间隔(单位:秒)  
  11.     enHeroPropConf_AtkRange,        // 攻击范围(半径)  
  12.     enHeroPropConf_UpgradeAtkBase,  // 升级攻击加成系数  
  13.     enHeroPropConf_UpgradeCostBase, // 升级消耗基础值  
  14. };  
  15. //--------------下面是类的一些成员-  
  16.     //**7**  
  17.     CC_SYNTHESIZE(EnumHeroType,_heroType,HeroType);      //英雄类型  
  18.     CC_SYNTHESIZE(int,_baseAtk,BaseAtk);                 //基础攻击  
  19.     CC_SYNTHESIZE(int,_curAtk,CurAtk);                   //当前攻击--eg:升级之后  
  20.     CC_SYNTHESIZE(int,_atkSpeed,AtkSpeed);               //攻击速度(间隔)  
  21.     CC_SYNTHESIZE(int,_atkRange,AtkRange);               //攻击范围(半径)  
  22.     CC_SYNTHESIZE(int,_upgradeCostBase,UpgradeConstBase);//升级消耗  
  23.     CC_SYNTHESIZE(float,_upgradeAtkBase,UpgradeAtkBase); //升级攻击加成  

同时在Init函数中

 

[cpp] view plaincopy
  1.     //**7**  
  2.     CsvUtil* csvUtil = CsvUtil::getInstance();  
  3.     Size csvSize = csvUtil->getFileRowColNum("cvs/Hero.cvs");  
  4.   
  5.     const char* chHeroID = __String::createWithFormat("%d",heroID)->getCString();  
  6.   
  7.     int line = csvUtil->findValueInWithLine(chHeroID,enHeroPropConf_ID,"cvs/Hero.cvs");  
  8.   
  9.     if(line < 0){  
  10.         return false;  
  11.     }  
  12.   
  13.     setID(heroID);  
  14.     setModeID(csvUtil->getInt(line,enHeroPropConf_ModelID,"cvs/Hero.cvs"));  
  15.     setBaseAtk(csvUtil->getInt(line,enHeroPropConf_BaseAtk,"cvs/Hero.cvs"));  
  16.     setCurAtk(getBaseAtk());  
  17.     setAtkSpeed(csvUtil->getInt(line,enHeroPropConf_AtkSpeed,"cvs/Hero.cvs"));  
  18.     setAtkRange(csvUtil->getInt(line,enHeroPropConf_AtkRange,"cvs/Hero.cvs"));  
  19.     setUpgradeAtkBase(csvUtil->getFloat(line,enHeroPropConf_UpgradeAtkBase,"cvs/Hero.cvs"));  
  20.     setUpgradeConstBase(csvUtil->getInt(line,enHeroPropConf_UpgradeCostBase,"cvs/Hero.cvs"));  
  21. //----------------升级----------------------  
  22.   
  23.     // 增加英雄攻击力   
  24.     setBaseAtk(getBaseAtk() * _upgradeAtkBase);  
  25.     setCurAtk(getBaseAtk());  

那么最后,在AppDelegate的构造函数中,

 

[cpp] view plaincopy
  1. AppDelegate::AppDelegate() {  
  2.     CC_SAFE_RETAIN(CsvUtil::getInstance());  
  3. }  
  4.   
  5. AppDelegate::~AppDelegate(){  
  6.     CC_SAFE_RELEASE(CsvUtil::getInstance());  
  7. }  

cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第七步---英雄要升级&属性--解析csv配置文件