首页 > 代码库 > 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级提升;每一次提升之后就弄一个动作覆盖上去
- 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**按钮事件
- 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);
- }
三个按钮,这里也要注意的是相对位置的放置问题,也就是son & parent的位置问题
三个按钮的函数比较简单,那么对应删除操作,是由——_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---由前两个配合完成最终解析;如果相应了解其具体工作,最好的方式就是一步步调试,那样很容易理解
---------------------------------------------------------------------------------------------------------------
那么看看那英雄的属性 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());
- }
cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第七步---英雄要升级&属性--解析csv配置文件