项目中要实现扑克牌随着手指翻牌的效果,当时想到的是利用类似帧动画来做,后面一个同事也提到可以用遮罩效果来实现,基本思路就是这两个了,一个是类似帧动画来实现,一个是遮罩实现;其实感觉还有更好的方式,就是OpenGL绘制实现,类似IOS和Android的翻书页效果,可惜能力有限;
类似帧动画的实现效果,算是比较简单的,但是有一个问题就是图片太多了,最后生成的包也太大了,所以中途也变成了用遮罩来实现,遮罩我也不太熟悉,有需要的可以看下网上其他资料,好了,不多说了,贴代码,里面有比较详细的注释,相信大家都看得懂的;
先是.h文件:
#ifndef POKEREFFECT_H
#define POKEREFFECT_H
#include "cocos2d.h"
USING_NS_CC;
class PokerEffect :public Layer
{
public:
static PokerEffect * create();
virtual bool init();
private:
virtual void onEnter();
bool onBegin(Touch * touch,Event * event);
void onMoved(Touch * touch,Event * event);
void onEnded(Touch * touch,Event * event);
public:
Sprite * maskedSpriteWithSprite(Sprite * textureSprite,Sprite * maskSprite, float Ratio);
private:
Sprite * mMaskedCal;//被遮罩出来的精灵
Sprite * mEffectSprite;//特效精灵
Size mVisibleSize;//屏幕可视的大小
float mOffset;// 手指点击的偏移
Point mTouchPoint;//手指点击的坐标
Point mSpritePoint;//精灵的坐标
Point mFirstTouchPoint;//触屏的第一个点坐标
Point mFirstImagePoint;//第一张图片的大小
std::vector<float> mOffsetPoint;//横向手指偏移量数组
std::vector<float> mMaskRatio;//横向遮罩比例
std::vector<float> mVerticalPoint;//竖向手指偏移量数组
std::vector<float> mVerticalMaskRatio;//竖向遮罩比例
ssize_t mIsRefresh;//是否刷新
bool isHorizontal;//是否横、竖
bool isRotation;//是否旋转
void initVector();//容器数值初始化
void setCardPokerEffect(int i,bool isHorizontal);//横向或竖向翻牌
void setCardRotation(Touch * touch);//牌旋转
};
#endif //
再是.cpp文件:
#include "PokerEffect.h"
PokerEffect* PokerEffect::create()
{
PokerEffect* pRet =new PokerEffect();
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet =NULL;
returnNULL;
}
}
bool PokerEffect::init()
{
if (!Layer::init())
{
returnfalse;
}
mVisibleSize =Director::getInstance()->getWinSize();
isHorizontal =true;
isRotation = true;
Sprite * oo =Sprite::create("background.jpg");
oo -> setPosition(mVisibleSize.width /2, mVisibleSize.height /2);
oo -> setScale(mVisibleSize.height / oo->getContentSize().height);
this ->addChild(oo);
initVector();
mIsRefresh = 0;
mEffectSprite =Sprite::create("01.png");
mEffectSprite ->setAnchorPoint(Point(0,1));
mEffectSprite ->setPosition(mVisibleSize.width /2 - mEffectSprite -> getContentSize().width /2, mVisibleSize.height /2 + mEffectSprite -> getContentSize().height /2);
mFirstImagePoint =mEffectSprite -> getPosition();
this ->addChild(mEffectSprite);
EventListenerTouchOneByOne * listener =EventListenerTouchOneByOne::create();
listener -> setSwallowTouches(true);
listener ->onTouchBegan = CC_CALLBACK_2(PokerEffect::onBegin,this);
listener ->onTouchMoved = CC_CALLBACK_2(PokerEffect::onMoved,this);
listener ->onTouchEnded = CC_CALLBACK_2(PokerEffect::onEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
returntrue;
}
boolPokerEffect::onBegin(Touch * touch,Event * event)
{
mTouchPoint = touch ->getLocation();
setCardRotation(touch);
returntrue;
}
voidPokerEffect::onMoved(Touch * touch,Event * event)
{
mOffset = touch->getLocation().y -mTouchPoint.y ;
int i =0;
if (mOffset >0)
{
for (; i <mOffsetPoint.size(); i++)
{
if (mOffset <=mOffsetPoint.at(i))
break;
}
}
if (mIsRefresh == i)
return;
if (mSpritePoint.y <=mFirstTouchPoint.y < (mSpritePoint.y +mEffectSprite -> getContentSize().height /10)) {
setCardPokerEffect(i,isHorizontal);
}
}
voidPokerEffect::onEnded(Touch * touch,Event * event)
{
}
voidPokerEffect::onEnter()
{
Layer::onEnter();
mMaskedCal =this -> maskedSpriteWithSprite(
Sprite::create("01.png"),
Sprite::create("mask_bg.png")
,1);
mMaskedCal ->setPosition(mVisibleSize.width /2, mVisibleSize.height /2);
mMaskedCal ->setVisible(false);
this ->addChild(mMaskedCal);
// mMaskedCal -> setTag(101);
}
// 设置牌旋转
voidPokerEffect::setCardRotation(Touch * touch)
{
// mTouchPoint = Point(0, touch -> getLocation().y - mOffsetPoint.at(mIsRefresh));
mFirstTouchPoint = touch -> getLocation();
mSpritePoint =Director :: getInstance() ->convertToGL(mEffectSprite ->getPosition());
if (mFirstTouchPoint.y >= (mSpritePoint.y + mEffectSprite -> getContentSize().height /5)
&& mEffectSprite ->getBoundingBox().containsPoint(mFirstTouchPoint)) {
if (isRotation) {
if (isHorizontal) {
mEffectSprite ->setPosition(Point(mVisibleSize.width /2 + mEffectSprite -> getContentSize().width /3, mVisibleSize.height /2 + mEffectSprite -> getContentSize().height /2));
mEffectSprite -> setRotation(90);
mEffectSprite -> setTag(1);
isHorizontal = false;
}else {
this -> removeChildByTag(1);
this -> removeChildByTag(2);
mEffectSprite = Sprite::create("01.png");
mEffectSprite -> setAnchorPoint(Point(0,1));
mEffectSprite ->setPosition(mVisibleSize.width /2 - mEffectSprite -> getContentSize().width /2, mVisibleSize.height /2 + mEffectSprite -> getContentSize().height /2);
mFirstImagePoint =mEffectSprite -> getPosition();
this -> addChild(mEffectSprite);
isHorizontal = true;
}
}
}
}
// 设置翻牌的动画
voidPokerEffect::setCardPokerEffect(int i,bool isHorizontal)
{
if (i < 10)
{
if (i < 1) {
isRotation = true;
}else {
isRotation = false;
}
mIsRefresh = i;
if (isHorizontal) {
mEffectSprite -> removeFromParent();
mEffectSprite = Sprite::create(String::createWithFormat("%02d.png", i + 1) -> getCString());
mEffectSprite -> setAnchorPoint(Point(0,1));
mEffectSprite ->setPosition(mFirstImagePoint);
this -> addChild(mEffectSprite);
mMaskedCal -> removeFromParent();
mMaskedCal =this -> maskedSpriteWithSprite(
Sprite::create("J01.png"),
Sprite::create("mask_bg.png"),
mMaskRatio.at(i));
mMaskedCal -> setAnchorPoint(Point(0,0));
mMaskedCal ->setPosition(mFirstImagePoint.x, (mFirstImagePoint.y - mEffectSprite -> getContentSize().height) - (1 - mMaskRatio.at(i)) *mMaskedCal -> getContentSize().height /2);
this->addChild(mMaskedCal);
}else {
mEffectSprite -> removeFromParent();
mEffectSprite = Sprite::create(String::createWithFormat("p%02d.png", i + 1) -> getCString());
mEffectSprite ->setPosition(Point(mVisibleSize.width /2 - mEffectSprite -> getContentSize().width /2, mFirstImagePoint.y));
mEffectSprite -> setAnchorPoint(Point(0,1));
mEffectSprite -> setTag(2);
this -> addChild(mEffectSprite);
mMaskedCal -> removeFromParent();
mMaskedCal =this->maskedSpriteWithSprite(
Sprite::create("J02.png"),
Sprite::create("mask_bg_vert.png"),
mVerticalMaskRatio.at(i));
mMaskedCal -> setAnchorPoint(Point(0,0.5));
mMaskedCal ->setPosition(mVisibleSize.width /2 - mEffectSprite -> getContentSize().width /2 + 25,
mEffectSprite -> getPosition().y -mEffectSprite -> getContentSize().height +mMaskedCal-> getContentSize().height *mVerticalMaskRatio.at(i) /2
);
this -> addChild(mMaskedCal);
}
}
}
// 初始化数值
voidPokerEffect::initVector()
{
//横向手指移动的距离
mOffsetPoint.push_back(0);
mOffsetPoint.push_back(20);
mOffsetPoint.push_back(90);
mOffsetPoint.push_back(110);
mOffsetPoint.push_back(150);
mOffsetPoint.push_back(220);
mOffsetPoint.push_back(270);
mOffsetPoint.push_back(300);
mOffsetPoint.push_back(310);
// 横向偏移量
mMaskRatio.push_back(0);
mMaskRatio.push_back(0);
mMaskRatio.push_back(0);
mMaskRatio.push_back(0);
mMaskRatio.push_back(0);
mMaskRatio.push_back(0.075);
mMaskRatio.push_back(0.175);
mMaskRatio.push_back(0.3);
mMaskRatio.push_back(0.475);
mMaskRatio.push_back(1);
//竖向手指移动的距离
// mVerticalPoint.push_back(0);
// mVerticalPoint.push_back(20);
// mVerticalPoint.push_back(70);
// mVerticalPoint.push_back(120);
// mVerticalPoint.push_back(200);
// mVerticalPoint.push_back(250);
// mVerticalPoint.push_back(300);
// mVerticalPoint.push_back(350);
// mVerticalPoint.push_back(400);
// 竖向偏移量
mVerticalMaskRatio.push_back(0);
mVerticalMaskRatio.push_back(0);
mVerticalMaskRatio.push_back(0);
mVerticalMaskRatio.push_back(0.055);
mVerticalMaskRatio.push_back(0.1);
mVerticalMaskRatio.push_back(0.155);
mVerticalMaskRatio.push_back(0.2);
mVerticalMaskRatio.push_back(0.245);
mVerticalMaskRatio.push_back(0.445);
mVerticalMaskRatio.push_back(1);
}
// 创建遮罩
Sprite *PokerEffect::maskedSpriteWithSprite(Sprite *textureSprite,Sprite *maskSprite , float Ratio)
{
maskSprite->setPosition(textureSprite->getContentSize().width / 2, textureSprite->getContentSize().height /2);
maskSprite->setScaleY(Ratio);
Point textureSpritePoint =Point(textureSprite->getContentSize().width /2, textureSprite->getContentSize().height /2 * Ratio);
textureSprite->setPosition(textureSpritePoint);
/*****************RenderTexture实现的四个步骤*****************/
//1、创建RenderTexture类,以像素为单位,指定你想要绘制的纹理的宽度和高度
RenderTexture *rt =RenderTexture::create(textureSprite->getContentSize().width, maskSprite->getContentSize().height);
//2、调用RenderTexture的begin方法来初始化渲染操作
rt->begin();
//{src color,destination color} 把将要画上去的颜色为“源颜色”,把原来的颜色称为“目标颜色”,“目标颜色”为屏幕:黑色,“源颜色”为maskSprite(即白色的图片,但是四角Alpha值减小),{GL_ONE,GL_ZERO}可知目标颜色*GL_ZERO,源颜色*GL_ONE,得到的为源颜色
BlendFunc blenfuc1 = {GL_ONE, GL_ZERO };
maskSprite->setBlendFunc(blenfuc1);
//“目标颜色”为屏幕:上面计算后的颜色,“源颜色”为textureSprite,{GL_DST_ALPHA,GL_ZERO}可知目标颜色*GL_ZERO,源颜色*GL_DST_ALPHA(屏幕的Alpha值)
BlendFunc blenfuc2 = {GL_DST_ALPHA, GL_ZERO };
textureSprite->setBlendFunc(blenfuc2);
//3、调用OpenGl函数来绘制实际的内容,这些OpenGl调用的最终都会绘制到屏幕之外去,而不会影响游戏中现在渲染的图像。
//如果想要渲染一个节点的话,可以直接调用某个节点的visit方法,如sprite—>visit(),然后这个函数会自动发射一些OpenGl函数指针给图形硬件去显示
maskSprite->visit();
textureSprite->visit();
//4、调用RenderTexture的end方法来借宿绘制操作,一旦你完成之后,rendertexture有一个sprite属性,你可以把它当Sprite来用
rt->end();
Sprite *retval =Sprite::createWithTexture(rt->getSprite()->getTexture());
retval->setFlippedY(true);//同时翻转y,因为纹理创建出来是倒的
return retval;
}
额,第一次写博客,不知道文件图片怎么弄,我把类文件和图片资源上传了,给个地址:http://download.csdn.net/detail/huluoboyou/7947075