< Cocos2d-x > カードをめくるようなアニメーション

Cocos2d-x バージョン:3.8.1


まずはどのようなものかご覧ください。


https://youtu.be/TgCKhkd9Oy0youtu.be


このような動きを行うために使用したのがActionと呼ばれるものです。

Actionを組み合わせることによりいかにもカードをめくっているかのように見せています。


組み合わせるときに使うのが以下のものになります。


Sequence
 …順番にActionを実行していく


Spawn
 …同時に複数Actionを実行していく


ソースコードは以下の通りです。

--- Trump.h ---

#ifndef __TRUMP_SCENE_H__
#define __TRUMP_SCENE_H__

#include "cocos2d.h"
#include <random>

// トランプクラス
class Trump : public cocos2d::Layer
{
public:
	enum
	{
		BACK,
		SELECT,
		RESULT,
	};


	CREATE_FUNC(Trump);
	static cocos2d::Scene* createScene();
	virtual bool init();

	bool onTouchBegan(cocos2d::Touch* pTouch, cocos2d::Event* pEvent);
	void onTouchEnded(cocos2d::Touch* pTouch, cocos2d::Event* pEvent);

	void openTrump(int tag);
};

#endif // __TRUMP_SCENE_H__

--- Trump.cpp ---


#include "Trump.h"

// cocos2d を省略
USING_NS_CC;

static const int MAX_TRUMP = 3;
static const int TRUMP_SIZE = 250;

// クリエイトメソッド
Scene* Trump::createScene()
{
	auto scene = Scene::create();
	auto layer = Trump::create();
	scene->addChild(layer);

	return scene;
}

// 初期化メソッド
bool Trump::init()
{
	if (!Layer::init())
	{
		return false;
	}

	// サイズの取得
	auto size = Director::getInstance()->getVisibleSize();

	// タッチリスナー(シングルタッチ)
	auto touchListener = EventListenerTouchOneByOne::create();
	touchListener->onTouchBegan = CC_CALLBACK_2(Trump::onTouchBegan, this);
	touchListener->onTouchEnded = CC_CALLBACK_2(Trump::onTouchEnded, this);
	this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(touchListener, this);

	// トランプを配置
	// 裏面のトランプを3枚配置します
	for (int i = 0; i < MAX_TRUMP; i++)
	{
		auto sprite = Sprite::create("Trump_Back.png");
		sprite->setPosition(Point(size.width / 2 - TRUMP_SIZE * (i - 1), size.height / 2));
		sprite->setTag(i);
		this->addChild(sprite,Trump::BACK);
	}

	// ボタン
	auto button = MenuItemImage::create("CloseNormal.png",
					    "CloseSelected.png",
					    [this](Ref* ref){				
					    Director::getInstance()->replaceScene(Trump::createScene());
	});

	button->setPosition(Point(size.width - button->getContentSize().width, button->getContentSize().height));

	auto menu = Menu::create(button, NULL);
	menu->setPosition(Point::ZERO);
	this->addChild(menu);

	return true;
}

void Trump::openTrump(int tag)
{
	// 選択された画像の取得
	auto selectTrump = this->getChildByTag(tag);
	this->reorderChild(selectTrump, Trump::SELECT);

	// 移動先の位置
	auto destPos = Director::getInstance()->getVisibleSize() / 2;

	// 表面に表示する画像を乱数で決める
	std::random_device device;
	std::mt19937 mt(device());
	std::uniform_int_distribution<int> dice(1, 3);

	std::stringstream fileName;
	fileName << "Trump_" << dice(mt) << ".png";

	log("%s", fileName.str().c_str());

        // 表面に表示される画像を作成
	auto resultTrump = Sprite::create(fileName.str().c_str());
	resultTrump->setPosition(destPos);
	resultTrump->setScale(1.5f);
        // 180度回転しているように見せるために角度を設定
	resultTrump->setRotationSkewY(-90.0f);
	this->addChild(resultTrump,Trump::RESULT);

	//
	// アニメーション
	//

	// 1 - 選択したトランプを中央に移動・拡大
	auto anim_Move = CallFunc::create([=]{
		auto move = MoveTo::create(0.6f, Vec3(destPos.width, destPos.height, 0.0f));
		auto scale = ScaleTo::create(0.6f, 1.5f);
		auto action = Spawn::create(move, scale ,NULL);
		selectTrump->runAction(action);
	});

	// 2 - 1と同時に選択外のトランプをフェードアウト・非表示
	auto anim_FadeOut = CallFunc::create([=]{
		for (int i = 0; i < MAX_TRUMP; i++)
		{
			// 選択トランプは除外
			if (i == tag)	continue;
			auto trump = this->getChildByTag(i);
			auto fadeOut = FadeOut::create(0.6f);
			auto visible = CallFunc::create([=]{
				trump->setVisible(false);
			});
			auto action = Sequence::create(fadeOut, visible, NULL);
			trump->runAction(action);
		}
	});

	// 3 - ディレイ
	auto delay = DelayTime::create(0.5f);

	// 4 - 選択したトランプを回転(90度)
	auto anim_Rota1 = CallFunc::create([=]{
		auto rota = RotateTo::create(0.3f, 0.0f,90.0f);
		selectTrump->runAction(rota);
	});

	// 5 - 表示するトランプを回転
	auto anim_Rota2 = CallFunc::create([=]{
		auto delay = DelayTime::create(0.3f);
		auto rota = RotateBy::create(0.3f, 0.0f, 90.0f);
		auto action = Sequence::create(delay, rota, NULL);
		resultTrump->runAction(action);
	});

	this->runAction(Sequence::create(anim_Move, anim_FadeOut, delay, anim_Rota1, anim_Rota2, NULL));
}


bool Trump::onTouchBegan(Touch* pTouch, Event* pEvent)
{
	return true;
}

void Trump::onTouchEnded(Touch* pTouch, Event* pEvent)
{
	// タッチ座標の取得
	auto touchPos = pTouch->getLocation();

	// シーンの取得
	// 0にはcocos2d::Cameraが入っているためシーンの取得時は1
	auto scene = Director::getInstance()->getRunningScene()->getChildren().at(1);
	for (int i = 0; i < MAX_TRUMP; i++)
	{
		auto sprite = scene->getChildByTag(i);

                // 表示していない場合はcontinue
		if (sprite->isVisible() != true) continue;

		if (sprite->getBoundingBox().containsPoint(touchPos))
		{
			// タッチした画像があったとき
			openTrump(i);
			break;
		}
	}
}


使用した画像名
Trump_Back.png
Trump_1.png
Trump_2.png
Trump_3.png