cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第六步---炮台&点击炮台加入英雄&英雄升级
/* 说明:
**1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记
**2.我也问过木头本人啦,他说:随便写,第一别全然照搬代码;第二能够说明是学习笔记---好人
**3.这里用cocos2d-x 3.0版本号重写,非常多地方不同,可是从重写过程中也非常好的学习了cocos2d-x
*/
***每一步相应的全部代码以及用到的资源都会打包在最后给出
***为避免代码过多,每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)
***能够依据设计思路(好吧,那名字太高大上。实际就是这一步要干啥)先自己实现---cocos2d-x本来就是如此,同样的功能有很多不同实现方法;先自己折腾是蛮不错的。
***为了方便移植到手机上,对于每一步都进行编译android測试;由于非常多时候代码在win32下能够,编译就会出错,给出的代码会是測试过后的。
本次笔记内容:
1、设计思路
2、代码&測试效果
3、下次内容预览
4、本次源代码&资源
一:设计思路
在前一步中,进入不同级别的游戏关卡之后,载入了之前自己编辑好的炮台的点
这一步中为这些点用真正的炮台来展示
然后点击炮台能加入英雄
1.首先为了后面的扩展,炮台也是应该有属性的,比方等级什么的。那么英雄和怪物相同也是,速度,防御等各种属性。那么能够抽离出一个基类Entity
2.这一步其中是关于炮台和英雄的 关系,那么首先来设计炮台;炮台继承实体,它通过精灵来展示,而且运行了一个动作---看起来高大上
3.那么在英雄管理器中,前面载入的点保存在容器里面啦,我们对容器遍历,对于每一个炮台坐标放一个炮台
4.然后是英雄,这一步中,我们仅仅实现点击炮台产生英雄,英雄的属性和配置文件Csv有关之后说
5.加入英雄之后,我们再次点击英雄,能够有一些操作,升级!删除!
二:代码&效果
首先看看基类:.h
<span style="font-size:14px;">class Entity : public Node{ public: Entity(); ~Entity(); void bindSprite(Sprite* sprite); Sprite* getSprite(); void hurtMe(int hurtValue); bool isDead(); Rect boundingBox(); protected: virtual void onDead(); virtual void onBindSprite(); virtual void onHurt(int hurtValue); private: Sprite* _sprite; bool _isDead; CC_SYNTHESIZE(int,_id,ID); CC_SYNTHESIZE(int,_modeID,ModeID); CC_SYNTHESIZE(__String*,_Name,Name); CC_SYNTHESIZE(int,_hp,HP); CC_SYNTHESIZE(int,_defense,Defense); CC_SYNTHESIZE(int,_speed,Speed); CC_SYNTHESIZE(int,_level,Level); };</span>.cpp
<span style="font-size:14px;">Entity::Entity(){ _sprite = NULL; _Name = __String::create(""); _hp = 1; _defense = 1; _isDead = false; _speed = 1; _level = 1; } Entity::~Entity(){ } void Entity::bindSprite(Sprite* sprite){ if(this->_sprite != NULL){ _sprite->removeFromParentAndCleanup(true); } this->_sprite = sprite; this->addChild(_sprite); //**6**假设子类绑定时须要其它作用,就重写以下的函数 onBindSprite(); } Sprite* Entity::getSprite(){ return this->_sprite; } void Entity::hurtMe(int hurtValue){ if(_isDead){ return ; } if(hurtValue <= getDefense()){ hurtValue = 1; } int curHP = getHP(); int afterHP = curHP-hurtValue; onHurt(hurtValue); if(afterHP > 0){ setHP(afterHP); } else{ _isDead = true; onDead(); } } Rect Entity::boundingBox(){ Node::boundingBox(); if(getSprite() == NULL){ return CCRectMake(0,0,0,0); } Point pos = getPosition(); Size size = getSprite()->getContentSize(); return CCRectMake(pos.x,pos.y,size.width,size.height); } bool Entity::isDead(){ return this->_isDead; } //空函数,留给子类 void Entity::onDead(){ } void Entity::onBindSprite(){ } void Entity::onHurt(int hurtValue){ }</span>能够看到它是有一些的属性,也有受伤、死亡、精灵什么的函数;后面对于不同的实体实现不同的功能
炮台TowerBorder.h
<span style="font-size:14px;">class TowerBorder : public Entity{ public: TowerBorder(); ~TowerBorder(); CREATE_FUNC(TowerBorder); virtual bool init(); bool isClickMe(Point pos);//检測是否点击了炮台 private: };</span>.cpp
<span style="font-size:14px;">TowerBorder::TowerBorder(){ } TowerBorder::~TowerBorder(){ } bool TowerBorder::init(){ __String* sFilePath = __String::createWithFormat("sprite/hero/border_%d.png",_level); Sprite* sprite = Sprite::create(sFilePath->getCString()); bindSprite(sprite); ActionInterval* rotateBy = RotateBy::create(25.0f,360,360); auto repeat = RepeatForever::create(rotateBy); sFilePath = __String::createWithFormat("sprite/hero/magic_border_%d.png",_level); sprite = Sprite::create(sFilePath->getCString()); sprite->setOpacity(80); sprite->runAction(repeat); this->addChild(sprite); return true; } bool TowerBorder::isClickMe(Point pos){ Size size = getSprite()->getContentSize(); Point borderPos = getPosition(); Point srcPos = Point(borderPos.x-size.width,borderPos.y+size.height); Point detPos = Point(borderPos.x+size.width,borderPos.y-size.height); if(pos.x>=srcPos.x && pos.x<=detPos.x && pos.y<=srcPos.y && pos.y>=detPos.y){ return true; } return false; }</span>然后測试一下:在HeroManager里面加入成员:
<span style="font-size:14px;">Vector<TowerBorder*> m_towerBorderList; void createTowerBorder();</span>那么在createTowerPos之后,我们调用createTowerBorder,也就是通过点来加入炮台
<span style="font-size:14px;">void HeroManager::createTowerPos(int curLevel){ /******************省略代码***************/ //**6** 载入全然部的点,那么就用点来加入炮台 createTowerBorder(); } void HeroManager::createTowerBorder(){ PosBase* tPos = NULL; for(auto ref : m_towerPosList){ tPos = dynamic_cast<PosBase*>(ref); if(tPos != NULL){ TowerBorder* border = TowerBorder::create(); border->setPosition(tPos->getPos()); this->addChild(border); m_towerBorderList.pushBack(border); } } }</span>把之前为了看到点坐标的 调式模式改为false,背景图片不设计透明度。执行測试例如以下:
接着,实现点击炮台加入英雄,先看看英雄
<span style="font-size:14px;">class Hero : public Entity{ public: Hero(); ~Hero(); static Hero* createFromCsvFileByID(int heroID); bool initFromCsvFileByID(int heroID); };</span>这里是依据ID来加入,也就是说有不同种类的英雄。可是本游戏仅仅有一种---这里理解了也能够自己扩展
<span style="font-size:14px;">Hero::Hero(){ } Hero::~Hero(){ } Hero* Hero::createFromCsvFileByID(int heroID){ Hero* hero = new Hero(); if(hero && hero->initFromCsvFileByID(heroID)){ hero->autorelease(); } else{ CC_SAFE_DELETE(hero); } return hero; } bool Hero::initFromCsvFileByID(int heroID){ Sprite* sprite = Sprite::create(__String::createWithFormat("sprite/hero/hero_%d.png",heroID)->getCString()); bindSprite(sprite); return true; }</span>那么我们理解加入英雄的过程:点击随意炮台,然后加入。可是,我们须要解决点击了那个炮台?
HeroManager里加入函数:
<span style="font-size:14px;">TowerBorder* findClickTowerBorder(Point pos){ TowerBorder* tBorder = NULL; for(auto ref : m_towerBorderList){ tBorder = dynamic_cast<TowerBorder*>(ref); if(tBorder){ if(tBorder->isClickMe(pos)){ return tBorder; } } } return NULL; }</span>同一时候,一个炮台仅仅有一个英雄,那么TowerBorder里面加入:
<span style="font-size:14px;">Hero* _hero; TowerBorder::TowerBorder(){ _hero = NULL; } TowerBorder::~TowerBorder(){ CC_SAFE_RELEASE(_hero); } Hero* getHero(){ return _hero;}; void bindHero(Hero* hero){ _hero = hero; };</span>那么,在管理器的触摸事件的end函数中:
<span style="font-size:14px;">bool HeroManager::initWithLevel(int curLevel){ /*****************省略***************/ listener->onTouchEnded = [=](Touch* touch,Event* event){ /*****************省略**************/ TowerBorder* clickBorder = findClickTowerBorder(pos); if(clickBorder == NULL){ return ; } if(clickBorder->getHero() == NULL){ Hero* hero = Hero::createFromCsvFileByID(1); hero->setPosition(clickBorder->getPosition()); this->addChild(hero); clickBorder->bindHero(hero); } }; /*************省略*************************************/ }</span>那么測试,点击炮台加入英雄,效果例如以下:
三:下节预览
看看Csv中的英雄属性怎样加到英雄身上---读取Csv&解析Csv文件,给英雄加入很多其它操作,让它升级,不想要了把它从炮台删除
--------------------------------
四:源代码&资源
-----------------------------------
个人愚昧观点,欢迎指正与讨论