• 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,然后绑定在炮台上,后面点击炮台,出现三个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。本次完啦

    三:下次内容预览

    英雄的属性看不出。是由于没有怪兽让它欺负。那么后面就要加入怪物,而且让它依照我们之前编辑的路线行走啦

    四:

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

    源代码&资源

    --------------------------------------
    个人愚昧观点。欢迎指正与讨论







  • 相关阅读:
    EF实现增删改查
    托管代码与非托管代码的区别
    堆、栈以及队列
    C#装箱和拆箱
    Leecode刷题之旅-C语言/python-349两个数组的交集
    Leecode刷题之旅-C语言/python-344反转字符串
    Leecode刷题之旅-C语言/python-217存在重复元素
    Leecode刷题之旅-C语言/python-206反转链表
    Leecode刷题之旅-C语言/python-204计数质数
    Leecode刷题之旅-C语言/python-203移除链表元素
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5157974.html
Copyright © 2020-2023  润新知