好久没更新了,抱歉,上篇讲到地图,时间过的太久不知道讲到哪理了,就直接从塔防游戏的最根本的”塔“来讲起吧!
首先我们定义一个防御塔的基类BaseTower
class BaseTower: public Sprite
我们要先确定一个塔所具备的属性,这些可以根据自己所设计的游戏需要来自行定义,例如:
CC_SYNTHESIZE(TowerType,towerType,TowerType); //类型 CC_SYNTHESIZE(Terrain*,myTerrain,MyTerrain); //建造点 CC_SYNTHESIZE(std::string,towerName,TowerName); //名称 CC_SYNTHESIZE(int,level,Level);//等级 CC_SYNTHESIZE(float,scope,Scope);//范围 CC_SYNTHESIZE(float,nextScope,NextScope);//升级后范围 CC_SYNTHESIZE(float,rate,Rate);//攻击速度 CC_SYNTHESIZE(int,force,Force);//攻击力 CC_SYNTHESIZE(int,updateMoney,UpdateMoney);//升级所需金钱 CC_SYNTHESIZE(int,buildMoney,BuildMoney);//售出时返还金钱
然后定义一些可能出现的公共方法,在不同的防御塔子类中实现:
public: virtual void updateTower(){};//升级防御塔(基础升级) virtual void sellTower();//售卖防御塔 virtual void removeTower();//移除防御塔 virtual bool init();//初始化防御塔 virtual void showTowerInfo();//显示防御塔信息 virtual void update1(){};//两种升级方向 virtual void update2(){}; virtual void setRallyPoint(Point point){};//兵营塔的设置集结点 protected: virtual void checkNearestMonster();//检测附近敌人 BaseMonster* nearestMonster; //附近的敌人 bool onTouchBegan(Touch *touch,Event *event); void onTouchEnded(Touch* touch,Event* event); virtual void showUpdateMenu(){};//显示升级选项 virtual void hideUpdateMenu();//隐藏 Sprite* terrain;//该塔的建造点 void setListener();//设置某些监听事件每个防御塔会有自己的shoot(float dt)之类的方法(根据防御塔类型不同而不同),通过schedule(schedule_selector(BaseTower::shoot),0.5f);定时调用,此时的0.5f就和防御塔的攻击速率有关,越短,攻击速度越快。
防御塔攻击敌人的思路参考了http://www.cocos.com/doc/tutorial/show?id=1108这篇文章,感谢作者
每次防御塔执行自己的shoot方法时,首先执行CheckNearestMonster来检测附近是否存在可以攻击的敌人
void BaseTower::checkNearestMonster() { auto instance = GameManager::getInstance(); auto monsterVector = instance->monsterVector;//全局Vector变量,用来存储当前关卡的敌人 auto currMinDistant = this->scope; nearestMonster = NULL; for(int i = 0; i < monsterVector.size(); i++) { auto monster = monsterVector.at(i); double distance = this->getParent()->getPosition().getDistance(monster->baseSprite->getPosition());//算坐标距离 if (distance < currMinDistant && monster->getAttackByTower()) { //当在塔的范围内,且怪物可以被攻击(某些地下怪物只有钻出地面可以被攻击) currMinDistant = distance;//设置最小距离,找到最近的怪物 <pre name="code" class="cpp"> nearestMonster <span style="font-family: Arial,Helvetica,sans-serif;">= monster</span>} }}
然后就是关键的shoot方法了,炮塔,弓箭塔,法师塔的原理基本一样,只是攻击的动画和轨迹计算不同而已,只有兵营塔略微不同,这些都将在下一章讲解。。。
通过setLinstener()给防御塔设置触摸时间
void BaseTower::setListener() { auto listener = EventListenerTouchOneByOne::create(); listener->onTouchBegan = CC_CALLBACK_2(BaseTower::onTouchBegan,this); listener->onTouchEnded = CC_CALLBACK_2(BaseTower::onTouchEnded,this); _eventDispatcher->addEventListenerWithSceneGraPHPriority(listener,terrain); }
对触摸事件进行相应处理:
不拦截Touchbool BaseTower::onTouchBegan(Touch *touch,Event *event) { return true; }
void BaseTower::onTouchEnded(Touch* touch,Event* event) { auto target = static_cast<Sprite*>(event->getCurrentTarget()); Point locationInNode = target->convertTouchToNodeSpace(touch); Size size = target->getContentSize(); Rect rect = Rect(0,size.width,size.height); if (rect.containsPoint(locationInNode))//当触摸点在防御塔内(即点击防御塔,目前只能通过此方法来判断是否点击防御塔) { static_cast<BaseMap*>(this->getParent()->getParent())->playerState->showTowerInfo(getTowerType());//调用父父布局(BaseMap)的PlayState层,显示防御塔信息 if(isUpdateMenuShown)//如果防御塔升级界面已经显示,则隐藏,某种显示 { hideUpdateMenu(); }else{ showUpdateMenu(); } }else{//触摸点在外面则隐藏防御塔升级界面 hideUpdateMenu(); } }