/* 说明:
**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,然后绑定在炮台上,后面点击炮台,出现三个button---升级、关闭、删除英雄
3.英雄的升级不仅仅是体如今外表,它也有属性。属性提升---属性就得从csv文件读取
5.因为这后面思路基本借鉴书上的,就不班门弄斧啦---直接在代码中结束
二:思路代码&效果图
首先给英雄升级函数。这里写得比較死,同一时候仅仅支持4级提升;每一次提升之后就弄一个动作覆盖上去
void Hero::upgrade(){ Sprite* sprite = getSprite(); if(sprite == NULL || _level >= 4) { return; } // 添加等级 _level++; // 英雄遮罩 if(_level == 2) { Sprite* heroTop = Sprite::create("sprite/hero/hero_top_1.png"); Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2); heroTop->setPosition(pos); sprite->addChild(heroTop); } if(_level == 3) { Sprite* heroTop = Sprite::create("sprite/hero/hero_top_2.png"); heroTop->setOpacity(255); Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2); heroTop->setPosition(pos); sprite->addChild(heroTop); ActionInterval* rotateBy = RotateBy::create(25.0f, 360, 360); ActionInterval* repeat = RepeatForever::create(rotateBy); heroTop->runAction(repeat); } if(_level == 4) { Point pos = ccp(sprite->getContentSize().width / 2, sprite->getContentSize().height / 2); Sprite* heroTop = Sprite::create("sprite/hero/hero_top_3.png"); heroTop->setPosition(pos); sprite->addChild(heroTop); ActionInterval* rotateBy = RotateBy::create(10.0f, 360, 360); ActionInterval* repeat = RepeatForever::create(rotateBy); heroTop->runAction(repeat); } }那么相应四个主要的不同效果例如以下:
lv1----lv2----lv3------lv4
效果是动态的动作
--------------------------------------------------------------
那么看看那操作器 TowerOperator;它须要和Hero以及炮台保存联系,须要这两个成员
class TowerOperator : public Node{ public: TowerOperator(); ~TowerOperator(); static TowerOperator* create(TowerBorder* towerBorder,Hero* hero); bool init(TowerBorder* towerBorder,Hero* hero); private: Hero* _hero; TowerBorder* _towerBorder; void createOprBtns(); //**7**button事件 void closeEvent(Ref* pSender,Control::EventType event); void upgradeEvent(Ref* pSender,Control::EventType event); void deleteEvent(Ref* pSender,Control::EventType event); };实现
TowerOperator::TowerOperator(){ _hero = NULL; _towerBorder = NULL; } TowerOperator::~TowerOperator(){ CC_SAFE_RELEASE(_hero); CC_SAFE_RELEASE(_towerBorder); } TowerOperator* TowerOperator::create(TowerBorder* towerBorder,Hero* hero){ TowerOperator* towerOperator = new TowerOperator(); if(towerOperator && towerOperator->init(towerBorder,hero)){ towerOperator->autorelease(); } else{ CC_SAFE_DELETE(towerOperator); } return towerOperator; } bool TowerOperator::init(TowerBorder* towerBorder, Hero* hero){ CC_SAFE_RETAIN(towerBorder); _towerBorder = towerBorder; CC_SAFE_RETAIN(hero); _hero = hero; createOprBtns(); return true; } void TowerOperator::createOprBtns(){ LabelTTF* title = LabelTTF::create("Close", "Arial", 25); auto m_pos = this->getPosition(); ControlButton* closeBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png")); closeBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED); closeBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(TowerOperator::closeEvent), Control::EventType::TOUCH_UP_INSIDE); closeBtn->setPosition( ccp(m_pos.x+100,m_pos.y)); this->addChild(closeBtn); title = CCLabelTTF::create("Delete", "Arial", 25); ControlButton* deleteBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png")); deleteBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED); deleteBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(TowerOperator::deleteEvent), Control::EventType::TOUCH_UP_INSIDE); deleteBtn->setPosition( ccp(m_pos.x-100,m_pos.y)); this->addChild(deleteBtn); title = CCLabelTTF::create("Upgrade", "Arial", 25); ControlButton* upgradeBtn = ControlButton::create(title, Scale9Sprite::create("Button/opr_btn_nor.png")); upgradeBtn->setBackgroundSpriteForState(Scale9Sprite::create("Button/opr_btn_light.png"), Control::State::HIGH_LIGHTED); upgradeBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(TowerOperator::upgradeEvent), Control::EventType::TOUCH_UP_INSIDE); upgradeBtn->setPosition( ccp(m_pos.x,m_pos.y+100)); this->addChild(upgradeBtn); } void TowerOperator::closeEvent(Ref* pSender,Control::EventType event){ CCLOG("close!"); this->removeFromParentAndCleanup(true); } void TowerOperator::upgradeEvent(Ref* pSender,Control::EventType event){ CCLOG("upgrade!"); _hero->upgrade(); } void TowerOperator::deleteEvent(Ref* pSender,Control::EventType event){ CCLOG("delete!"); _towerBorder->deleteHero(); this->removeFromParentAndCleanup(true); }三个button,这里也要注意的是相对位置的放置问题,也就是son & parent的位置问题
三个button的函数比較简单。那么相应删除操作,是由——_towerBorder去完毕的。其函数为:
void TowerBorder::deleteHero(){ _hero->removeFromParentAndCleanup(true); CC_SAFE_RELEASE_NULL(_hero); }而且。要注意,不要用_hero直接从parent删除,不然导致这个炮台下次无法继续加入
那么我们的操作器得展示出来。回忆往炮台加英雄的时候,是在触摸事件中,次炮台没有英雄的时候就加入,那么假设有。我们就显示操作器就是啦:
void TowerBorder::showOperator(){ auto towerOperator = TowerOperator::create(this,_hero); CC_SAFE_RETAIN(towerOperator); towerOperator->setPosition(ccp(0,0)); this->addChild(towerOperator); } //这里的setPostion以及操作器里面的setPos也和前面说过的相对位置有关 bool HeroManager::initWithLevel(int curLevel){ /********************省略*****************/ listener->onTouchEnded = [=](Touch* touch,Event* event){ /********************省略*****************/ if(clickBorder->getHero() == NULL){ Hero* hero = Hero::createFromCsvFileByID(1); hero->setPosition(clickBorder->getPosition()); this->addChild(hero); clickBorder->bindHero(hero); } else{ clickBorder->showOperator(); } }; _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this); //------------------------------------------------------------ return true; }效果例如以下:
那么,我们英雄的升级有了外表的体现啦
但是我们的英雄一直没有属性上的配置-----------------这要通过csv 来弄。
首先须要说明的是:
csv是一种简单的文件。你能够用Excel 来弄,外观像表格,最后保存的格式为csv就是的。
可是用记事本打开,就会发现实际上是用逗号分隔开的如图:
----------------------
那么这里的csv须要解析,然后放到我们的cocos2d-x 里面。使用这些属性。
详细的也是木头书上的。我这里只是多说;可是在3.0版本号中,也改动了不少地方。同一时候为了移植到手机上,也做了对应的改动;这里解析csv文件有三个类:
FileLoadUtil---文件载入 、StringUtil---字符串解析 、CsvUtil---由前两个配合完毕终于解析;假设对应了解其详细工作,最好的方式就是一步步调试。那样非常easy理解
---------------------------------------------------------------------------------------------------------------
那么看看那英雄的属性 Hero.h里面:
enum EnumHeroType{ en_HeroType_Normal }; enum EnumHeroPropConfType{ enHeroPropConf_ID, // 英雄ID enHeroPropConf_Name, // 英雄名字 enHeroPropConf_Type, // 英雄类型 enHeroPropConf_ModelID, // 英雄模型ID enHeroPropConf_BaseAtk, // 基础攻击力 enHeroPropConf_AtkSpeed, // 攻击间隔(单位:秒) enHeroPropConf_AtkRange, // 攻击范围(半径) enHeroPropConf_UpgradeAtkBase, // 升级攻击加成系数 enHeroPropConf_UpgradeCostBase, // 升级消耗基础值 }; //--------------以下是类的一些成员- //**7** CC_SYNTHESIZE(EnumHeroType,_heroType,HeroType); //英雄类型 CC_SYNTHESIZE(int,_baseAtk,BaseAtk); //基础攻击 CC_SYNTHESIZE(int,_curAtk,CurAtk); //当前攻击--eg:升级之后 CC_SYNTHESIZE(int,_atkSpeed,AtkSpeed); //攻击速度(间隔) CC_SYNTHESIZE(int,_atkRange,AtkRange); //攻击范围(半径) CC_SYNTHESIZE(int,_upgradeCostBase,UpgradeConstBase);//升级消耗 CC_SYNTHESIZE(float,_upgradeAtkBase,UpgradeAtkBase); //升级攻击加成同一时候在Init函数中
//**7** CsvUtil* csvUtil = CsvUtil::getInstance(); Size csvSize = csvUtil->getFileRowColNum("cvs/Hero.cvs"); const char* chHeroID = __String::createWithFormat("%d",heroID)->getCString(); int line = csvUtil->findValueInWithLine(chHeroID,enHeroPropConf_ID,"cvs/Hero.cvs"); if(line < 0){ return false; } setID(heroID); setModeID(csvUtil->getInt(line,enHeroPropConf_ModelID,"cvs/Hero.cvs")); setBaseAtk(csvUtil->getInt(line,enHeroPropConf_BaseAtk,"cvs/Hero.cvs")); setCurAtk(getBaseAtk()); setAtkSpeed(csvUtil->getInt(line,enHeroPropConf_AtkSpeed,"cvs/Hero.cvs")); setAtkRange(csvUtil->getInt(line,enHeroPropConf_AtkRange,"cvs/Hero.cvs")); setUpgradeAtkBase(csvUtil->getFloat(line,enHeroPropConf_UpgradeAtkBase,"cvs/Hero.cvs")); setUpgradeConstBase(csvUtil->getInt(line,enHeroPropConf_UpgradeCostBase,"cvs/Hero.cvs")); //----------------升级---------------------- // 添加英雄攻击力 setBaseAtk(getBaseAtk() * _upgradeAtkBase); setCurAtk(getBaseAtk());那么最后。在AppDelegate的构造函数中,
AppDelegate::AppDelegate() { CC_SAFE_RETAIN(CsvUtil::getInstance()); } AppDelegate::~AppDelegate(){ CC_SAFE_RELEASE(CsvUtil::getInstance()); }OK。本次完啦
三:下次内容预览
英雄的属性看不出。是由于没有怪兽让它欺负。那么后面就要加入怪物,而且让它依照我们之前编辑的路线行走啦
四:
-----------------------------------
--------------------------------------
个人愚昧观点。欢迎指正与讨论