接下来添加攻击按钮用于执行攻击动作。
同时修复了上一版移动时的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);elsethis->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 objectauto 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);elsethis->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 objectauto 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; #endifDirector::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"); }