As above, add a map and add it directly to the map layer. I set AnchorPoint at (0,0) to calculate coordinates.
mapSprite = Sprite::createWithSpriteFrameName(String::createWithFormat("Stage_%d.png",level+1)->getCString()); mapSprite->setAnchorPoint(Point(0,0)); mapSprite->setPosition(Point(0,0)); addChild(mapSprite);
This chapter focuses on the implementation of two fixed and store skills
First, there are two fixed skills, with meteorites as an example
First add the Key Picture Wizard
stoneSprite = Sprite::createWithSpriteFrameName("power_portrait_fireball_0001.png"); stoneSprite->setAnchorPoint(Point(0,0)); stoneSprite->setPosition(Point(10,-20)); stoneSprite->setName("inactive"); //Determine if the countdown is complete completeStone = false; addChild(stoneSprite,1);
Then there's the countdown mask, implemented in ProgressTimer, on top of the key picture Genie
stoneTimer = ProgressTimer::create(Sprite::createWithSpriteFrameName("power_loading.png")); stoneTimer->setAnchorPoint(Point(0,0)); //Turn clockwise stoneTimer->setReverseDirection(true); stoneTimer->setPosition(Point(10,-20)); stoneTimer->setPercentage(100);//Percentage of original this->addChild(stoneTimer,1);
Add timer to update ProgressTimer status
void PlayerStateMenu::updateStoneProgress(float Dt){ stoneTimer->setPercentage(stoneTimer->getPercentage() - Dt*2);//Update Progress 2 if (stoneTimer->getPercentage()==0) { this->unschedule(schedule_selector(PlayerStateMenu::updateStoneProgress));//Cancel timer completeStone = true; } return; }
Schdule when you want to start, like after the first enemy wave
Add touch response
auto stoneListener = EventListenerTouchOneByOne::create(); stoneListener->onTouchBegan = [&](Touch* touch, Event* event){ auto target = static_cast<Sprite*>(event->getCurrentTarget()); Point locationInNode = target->convertTouchToNodeSpace(touch); Size size = target->getContentSize(); Rect rect = Rect(0, 0, size.width, size.height); //If the first click clicks if(rect.containsPoint(locationInNode)){ //If cooling ends if(completeStone == true){ //Remove other skills to touch monitor mTouchLayer->removeAllListener(); if(stoneSprite->getName() == "inactive"){ //Set to Click Status stoneSprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("power_portrait_fireball_0002.png")); //Change state TAG stoneSprite->setName("active"); //Change the other 2 key states /**** ****/ //Touch Layer Set up Meteorite Skill Monitoring mTouchLayer->setFireBallTouchShield(); //Second click, cancel }else{ mTouchLayer->removeFireBallTouchShield(); stoneSprite->setSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("power_portrait_fireball_0001.png")); stoneSprite->setName("inactive"); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} return true; } return false; }; stoneListener->onTouchEnded = [&](Touch* touch, Event* event){ }; //Touch phagocytosis stoneListener->setSwallowTouches(true); _eventDispatcher->addEventListenerWithSceneGraphPriority(stoneListener,stoneSprite);
When the countdown ends, set completeStone to true, and only then click the key will trigger.
Click Skills to add an EventListenerTouchOneByOne to the touch layer, covering the entire touch layer, which is executed when the map is clicked
Let's look at the touch layer
Here I just intercepted the part about the meteorite and the moving mapclass TouchLayer :public Layer { public: virtual bool init(); CREATE_FUNC(TouchLayer); EventListenerTouchOneByOne* touchlistener; EventListenerTouchOneByOne* FiereBalllistener; void setFireBallTouchShield(); void removeFireBallTouchShield(); bool onFireBallTouchBegan(Touch* touch, Event* event); void onFireBallTouchEnded(Touch* touch, Event* event); bool isFlag; bool onTouchBegan(Touch* touch, Event* event); void onTouchEnded(Touch* touch, Event* event); void onTouchMoved(Touch* touch, Event* event); Size winSize; bool isMoved; void removeAllListener(); };
Add touch monitoring layer in BaseMap
void BaseMap::initTouchLayer() { mTouchLayer = TouchLayer::create(); mTouchLayer->setContentSize(mapSprite->getContentSize()); mTouchLayer->setAnchorPoint(Point(0,0)); mTouchLayer->setPosition(Point(0,0)); addChild(mTouchLayer,99); }
Add Map Move Time Touch
touchlistener = EventListenerTouchOneByOne::create(); touchlistener->onTouchBegan = CC_CALLBACK_2(TouchLayer::onTouchBegan, this); touchlistener->onTouchEnded = CC_CALLBACK_2(TouchLayer::onTouchEnded, this); touchlistener->onTouchMoved = CC_CALLBACK_2(TouchLayer::onTouchMoved, this); touchlistener->setSwallowTouches(true); _eventDispatcher->addEventListenerWithFixedPriority(touchlistener,-1); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchlistener,this);
void TouchLayer::onTouchEnded(Touch* touch, Event* event) { <span style="white-space:pre"> </span>touchlistener->setSwallowTouches(isMoved); isMoved = false; } void TouchLayer::onTouchMoved(Touch* touch, Event* event) { // Calculating the sliding increment during sliding auto diff = touch->getDelta(); //Finger movement correction because finger touch is not as fixed as mouse touch if(abs(diff.x) >5|| abs(diff.y) >5){ isMoved = true; } // Get the current bgSprite location auto currentPos = this->getParent()->getPosition(); // Get where bgSprite should be after sliding auto pos = currentPos + diff; //Boundary control, constraining pos position pos.x = MIN(pos.x, 0); pos.x = MAX(pos.x, -1200 + winSize.width); pos.y = MIN(pos.y, 0); pos.y = MAX(pos.y, -1000 + winSize.height); // Reset Map Layer Location this->getParent()->setPosition(pos); }
IsMoved is true when the finger moves over the touch layer, which is set SwallowTouches (isMoved) will swallow up other touch events
This is to ensure that when you move past or end up happening to be at a touch point, other touch events will not be triggered (for example, when you move your finger exactly on a defense tower, you will not pop up the upgrade layer of the tower)
Additionally, it does not trigger skill event monitoring when moving, so you can select the skill release location after moving.
void TouchLayer::setFireBallTouchShield() { //Call this method to create a meteorite skill touch time FiereBalllistener = EventListenerTouchOneByOne::create(); FiereBalllistener->onTouchBegan = CC_CALLBACK_2(TouchLayer::onFireBallTouchBegan, this); FiereBalllistener->onTouchEnded = CC_CALLBACK_2(TouchLayer::onFireBallTouchEnded, this); FiereBalllistener->setSwallowTouches(true); //Settings higher than mobile touch events _eventDispatcher->addEventListenerWithFixedPriority(FiereBalllistener,1); _eventDispatcher->addEventListenerWithSceneGraphPriority(FiereBalllistener,this); } void TouchLayer::removeFireBallTouchShield() { //Remove this listening time when skills are used if(FiereBalllistener!=NULL) _eventDispatcher->removeEventListener(FiereBalllistener); } bool TouchLayer::onFireBallTouchBegan(Touch* touch, Event* event) { //Return to TRUE directly, intercept other times return true; } void TouchLayer::onFireBallTouchEnded(Touch* touch, Event* event) { //Play Sound SoundManager::playFireballUnleash(); //Create three meteorites auto fireBall1 = FireBall::create(); addChild(fireBall1); fireBall1->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(-30,300)); auto fireBall2 = FireBall::create(); addChild(fireBall2); fireBall2->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(0,350)); auto fireBall3 = FireBall::create(); addChild(fireBall3); fireBall3->shoot(static_cast<TouchLayer*>(event->getCurrentTarget())->convertTouchToNodeSpace(touch)+Point(30,280)); //Get the parent's player state layer after the crash, call startStone, restart the timing, and reset the ProgressTimer mask static_cast<BaseMap*>(this->getParent())->playerState->startStone(); //Remove this listening event removeFireBallTouchShield(); }
That's almost what I do with whole skill monitoring plus touch-and-move
Store skills, summoning soldiers and other skills are the same way, but the skills used are different ~Other skills, such as freezing enemies, summoning soldiers, etc., will be introduced in the corresponding modules
I wrote this for the time being today, and there are some hard-working internships waiting for me to find them
Reprinted at: https://my.oschina.net/wuhaoyu/blog/607832