接下来添加攻击按钮用于执行攻击动作。
同时修复了上一版移动时的bug。
修复后的Player::walkTo()函数:
void Player::walkTo(Vec2 dest) { if (_seq) this->stopAction(_seq); auto curPos = this->getPosition(); if (curPos.x > dest.x) this->setFlippedX(true); else this->setFlippedX(false); auto diff = dest - curPos; auto time = diff.getLength() / _speed; auto moveTo = MoveTo::create(time, dest); auto func = [&]() { this->stopAllActions(); this->playAnimationForever("stay"); _seq = nullptr; }; auto callback = CallFunc::create(func); this->stopAllActions(); this->playAnimationForever("walk"); _seq = Sequence::create(moveTo, callback, nullptr); this->runAction(_seq); }
在MainScene::init()函数中添加了攻击按钮:
auto attackItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(MainScene::attackCallback, this)); attackItem->setPosition(Vec2(origin.x + visibleSize.width - attackItem->getContentSize().width/2 , origin.y + attackItem->getContentSize().height/2)); // create menu, it's an autorelease object auto menu = Menu::create(attackItem, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 1);
增加了攻击的回调函数:
void MainScene::attackCallback(Ref* pSender) { _hero->stopAllActions(); _hero->playAnimation("attack"); }
增加了Player::playAnimation()函数,执行了一次动作之后又回返回重复执行"stay"。
void Player::playAnimation(std::string animationName) { auto str = String::createWithFormat("%s-%s", _name.c_str(), animationName.c_str())->getCString(); bool exist = false; for (int i = 0; i < _animationNum; i ++) { if (animationName == _animationNames[i]) { exist = true; break; } } if (exist == false) return; auto animation = AnimationCache::getInstance()->getAnimation(str); auto func = [&]() { this->stopAllActions(); this->playAnimationForever("stay"); _seq = nullptr; }; auto callback = CallFunc::create(func); auto animate = Sequence::create(Animate::create(animation), callback,NULL); this->runAction(animate); }
效果:
#ifndef __Player__ #define __Player__ #include "cocos2d.h" USING_NS_CC; class Player : public Sprite { public: enum PlayerType { HERO, ENEMY }; bool initWithPlayerType(PlayerType type); static Player* create(PlayerType type); void addAnimation(); void playAnimationForever(std::string animationName); void playAnimation(std::string animationName); void walkTo(Vec2 dest); private: PlayerType _type; std::string _name; int _animationNum = 5; float _speed; std::vector<int> _animationFrameNums; std::vector<std::string> _animationNames; Sequence* _seq; }; #endif
#include "Player.h" #include <iostream> bool Player::initWithPlayerType(PlayerType type) { std::string sfName = ""; std::string animationNames[5] = {"attack", "dead", "hit", "stay", "walk"}; _animationNames.assign(animationNames,animationNames+5); switch (type) { case PlayerType::HERO: { _name = "hero"; sfName = "hero-stay0000.png"; int animationFrameNums[5] = {10, 12, 15, 30, 24}; _animationFrameNums.assign(animationFrameNums, animationFrameNums+5); _speed = 125; break; } case PlayerType::ENEMY: { _name = "enemy"; sfName = "enemy-stay0000.png"; int animationFrameNums[5] = {21, 21, 24, 30, 24}; _animationFrameNums.assign(animationFrameNums, animationFrameNums+5); break; } } this->initWithSpriteFrameName(sfName); this->addAnimation(); return true; } Player* Player::create(PlayerType type) { Player* player = new Player(); if (player && player->initWithPlayerType(type)) { player->autorelease(); return player; } else { delete player; player = NULL; return NULL; } } void Player::addAnimation() { auto animation = AnimationCache::getInstance()->getAnimation(String::createWithFormat("%s-%s", _name.c_str(), _animationNames[0].c_str())->getCString()); if (animation) return; for (int i = 0; i < _animationNum; i ++) { auto animation = Animation::create(); animation->setDelayPerUnit(1.0f / 10.0f); for (int j = 0; j < _animationFrameNums[i]; j ++) { auto sfName = String::createWithFormat("%s-%s%04d.png", _name.c_str(), _animationNames[i].c_str(), j)->getCString(); animation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(sfName)); if (!animation) log("hello ha ha"); } AnimationCache::getInstance()->addAnimation(animation, String::createWithFormat("%s-%s", _name.c_str(), _animationNames[i].c_str())->getCString()); } } void Player::playAnimationForever(std::string animationName) { auto str = String::createWithFormat("%s-%s", _name.c_str(), animationName.c_str())->getCString(); bool exist = false; for (int i = 0; i < _animationNum; i ++) { if (animationName == _animationNames[i]) { exist = true; break; } } if (exist == false) return; auto animation = AnimationCache::getInstance()->getAnimation(str); auto animate = RepeatForever::create(Animate::create(animation)); this->runAction(animate); } void Player::playAnimation(std::string animationName) { auto str = String::createWithFormat("%s-%s", _name.c_str(), animationName.c_str())->getCString(); bool exist = false; for (int i = 0; i < _animationNum; i ++) { if (animationName == _animationNames[i]) { exist = true; break; } } if (exist == false) return; auto animation = AnimationCache::getInstance()->getAnimation(str); auto func = [&]() { this->stopAllActions(); this->playAnimationForever("stay"); _seq = nullptr; }; auto callback = CallFunc::create(func); auto animate = Sequence::create(Animate::create(animation), callback,NULL); this->runAction(animate); } void Player::walkTo(Vec2 dest) { if (_seq) this->stopAction(_seq); auto curPos = this->getPosition(); if (curPos.x > dest.x) this->setFlippedX(true); else this->setFlippedX(false); auto diff = dest - curPos; auto time = diff.getLength() / _speed; auto moveTo = MoveTo::create(time, dest); auto func = [&]() { this->stopAllActions(); this->playAnimationForever("stay"); _seq = nullptr; }; auto callback = CallFunc::create(func); this->stopAllActions(); this->playAnimationForever("walk"); _seq = Sequence::create(moveTo, callback, nullptr); this->runAction(_seq); }
#ifndef __MainScene__ #define __MainScene__ #include "cocos2d.h" #include "Player.h" USING_NS_CC; class MainScene : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); void menuCloseCallback(cocos2d::Ref* pSender); CREATE_FUNC(MainScene); bool onTouchBegan(Touch* touch, Event* event); void attackCallback(Ref* pSender); private: Player* _hero; Player* _enemy; EventListenerTouchOneByOne* _listener_touch; }; #endif
#include "MainScene.h" #include "FSM.h" Scene* MainScene::createScene() { auto scene = Scene::create(); auto layer = MainScene::create(); scene->addChild(layer); return scene; } bool MainScene::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("images/role.plist","images/role.png"); Sprite* background = Sprite::create("images/background.png"); background->setPosition(origin + visibleSize/2); this->addChild(background); //add player _hero = Player::create(Player::PlayerType::HERO); _hero->setPosition(origin.x + _hero->getContentSize().width/2, origin.y + visibleSize.height/2); this->addChild(_hero); //add enemy1 _enemy = Player::create(Player::PlayerType::ENEMY); _enemy->setPosition(origin.x + visibleSize.width - _enemy->getContentSize().width/2, origin.y + visibleSize.height/2); this->addChild(_enemy); _hero->playAnimationForever("stay"); _enemy->playAnimationForever("stay"); _listener_touch = EventListenerTouchOneByOne::create(); _listener_touch->onTouchBegan = CC_CALLBACK_2(MainScene::onTouchBegan,this); _eventDispatcher->addEventListenerWithSceneGraphPriority(_listener_touch, this); auto attackItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(MainScene::attackCallback, this)); attackItem->setPosition(Vec2(origin.x + visibleSize.width - attackItem->getContentSize().width/2 , origin.y + attackItem->getContentSize().height/2)); // create menu, it's an autorelease object auto menu = Menu::create(attackItem, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 1); return true; } void MainScene::menuCloseCallback(cocos2d::Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); return; #endif Director::getInstance()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } bool MainScene::onTouchBegan(Touch* touch, Event* event) { Vec2 pos = this->convertToNodeSpace(touch->getLocation()); _hero->walkTo(pos); log("MainScene::onTouchBegan"); return true; } void MainScene::attackCallback(Ref* pSender) { _hero->stopAllActions(); _hero->playAnimation("attack"); }