我先描述一下这个问题:
拿之前做的卡牌游戏来说,如果一方场上有3张牌,那么肯定要以一种顺序来播放攻击动画,我是以从左到右的方式。
我的解决方式是向每张牌都传递一个延时参数,然后在runAction的时候使用DelyTime,但是这种方法太麻烦!
现在说说更好的方法吧:
基本思路是vector与callfunc相结合。
一:
先在类里定义数据和函数
- std::vector<std::vector<int>> v_action;//储存精灵TAG和动画TAG的容器
- void push_action(int sprite_tag,int action_tag);//添加动作序列
- void run_action(int sprite_tag,int action_tag);//播放动作
- void next_action();//下一个动作
- Sequence* run(int action_tag);//根据TAG返回动作
- bool isRunAction;//是否正在播放动作
二:
在init初始化参数
- //还没有播放动作
- isRunAction=false;
- Size visibleSize = Director::getInstance()->getVisibleSize();
- Vec2 origin = Director::getInstance()->getVisibleOrigin();
- //演员一
- auto actor1 = Sprite::create("CloseNormal.png");
- actor1->setTag(11);
- actor1->setPosition(250,visibleSize.height/2);
- this->addChild(actor1,2);
- //演员二
- auto actor2 = Sprite::create("CloseNormal.png");
- actor2->setTag(22);
- actor2->setPosition(300,visibleSize.height/2);
- this->addChild(actor2,2);
- //演员一跳跃
- auto play1 = MenuItemImage::create(
- "CloseNormal.png","CloseSelected.png",CC_CALLBACK_1(HelloWorld::menuCallback,this));
- play1->setTag(1);
- play1->setPosition(250,visibleSize.height/5);
- //演员二跳跃
- auto play2 = MenuItemImage::create(
- "CloseNormal.png",this));
- play2->setTag(2);
- play2->setPosition(300,visibleSize.height/5);
- auto closeItem = MenuItemImage::create(
- "CloseNormal.png",CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
- closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2,origin.y + closeItem->getContentSize().height/2));
- // create menu,it's an autorelease object
- auto menu = Menu::create(play1,play2,closeItem,NULL);
- menu->setPosition(Vec2::ZERO);
- this->addChild(menu,1);
- void HelloWorld::menuCallback(Ref* pSender)
- {
- auto menuItem = (MenuItemImage*)pSender;
- Sprite* actor;
- switch (menuItem->getTag())
- {
- case 1:
- push_action(11,1);
- break;
- case 2:
- push_action(22,1);
- break;
- default:
- break;
- }
- }
这里使用了push_action函数,作用是播放动作或者将操作存入容器:
- void HelloWorld::push_action(int sprite_tag,int action_tag)
- {
- if(isRunAction==false)//如果没有在播放动作,那么直接播放此动作
- {
- isRunAction=true;
- run_action(sprite_tag,action_tag);
- }
- else//如果正在播放,那么将此动作存入容器
- {
- std::vector<int> v_sprite;
- v_sprite.push_back(sprite_tag);
- v_sprite.push_back(action_tag);
- v_action.push_back(v_sprite);
- }
- }
注释已经比较详细了~
我们先看看run_action函数里面有什么吧:
- void HelloWorld::run_action(int sprite_tag,int action_tag)
- {
- auto actor = (Sprite*)getChildByTag(sprite_tag);
- auto squence = Sequence::create(run(action_tag),CallFunc::create(this,callfunc_selector(HelloWorld::next_action)),NULL);
- actor->runAction(squence);
- }
函数的作用是根据传入的两个tag播放动作,然后调用next_action:
- void HelloWorld::next_action()
- {
- if(v_action.empty())
- {
- isRunAction=false;
- }
- else
- {
- std::vector<int > a;
- a=v_action.at(0);
- int sprite_tag=a.at(0);
- int action_tag=a.at(1);
- std::vector<std::vector<int>>::iterator it = v_action.begin();
- v_action.erase(it);
- run_action(sprite_tag,action_tag);
- }
- }
如果容器里没有数据则说明接下来没有动作可以播放了,则把isRunAction赋为false,下次就可以直接播放动作。
如果容器里有数据,我们先把这项数据取出然后删除它,然后再调用run_action。
最后我们看看run里面有什么吧:
- Sequence* HelloWorld::run(int action_tag)
- {
- switch (action_tag)
- {
- case 1:
- return Sequence::create(MoveBy::create(0.2,Vec2(0,100)),MoveBy::create(0.2,-100)),NULL);
- default:
- break;
- }
- }
很简单,就是一个动作,当然我们可以根据需要增加。(注意返回参数是Sequence,所以想播放其他动画就改函数吧)
现在看看效果:
完成!