首页 > 代码库 > Cocos2d-x3.1TestCpp之MotionStreakTest Demo分析

Cocos2d-x3.1TestCpp之MotionStreakTest Demo分析

1、构成代码

VisibleRect.h
VisibleRect.cpp
AppDelegate.h
AppDelegate.cpp
HelloWorldScene.h
HelloWorldScene.cpp
MotionStreakDemo.h
MotionStreakDemo.cpp

2、代码分析

(1)VisibleRect、Appdelegate的代码均为TestCpp提供代码;
(2)HelloWorldScene.cpp中只需把上一篇Cocos2d-x3.1TestCpp之NewRenderTest Demo分析代码中HelloWorldScene.cpp中touchEvent函数中的NewRendererDemo换成本次Demo的基类MotionStreakDemo

3、MotionStreakDemo代码分析

(1).h文件
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "VisibleRect.h"
USING_NS_CC;
using namespace ui;
//基类Scene,所有测试Demo继承Layer,均加载到该基类Scene上,点击上一个、下一个、当前标签均通过场景切换来实现页面变化
class MotionStreakDemo : public Scene
{
public:
    CREATE_FUNC(MotionStreakDemo);
    virtual bool init();
};

class BaseTest : public cocos2d::Layer
{
public:
    CREATE_FUNC(BaseTest);
    std::string title() const;//标题
    virtual std::string subtitle() const;//副标题
    
    void restartCallback(Ref* sender);//重新执行当前test
    void nextCallback(Ref* sender);//下一个test
    void backCallback(Ref* sender);//上一个test
    void modeCallback(Ref* sender);
    virtual bool init();
    void menuCloseCallback(cocos2d::Ref* pSender);//关闭菜单回调函数
    
protected:
    MotionStreak* streak;
};
//第一个test,类似于地球绕着太阳转的效果
class MotionStreakTest1 : public BaseTest
{
public:
    CREATE_FUNC(MotionStreakTest1);
    virtual bool init();
    void onUpdate(float delta);
    virtual std::string subtitle() const override;
protected:
    Node* _root;
    Node* _target;
};
//第二个test,类似于画板
class MotionStreakTest2 : public BaseTest
{
public:
    CREATE_FUNC(MotionStreakTest2);
    virtual bool init();
    void onTouchesMoved(const std::vector<Touch*>& touches,Event* event);
    virtual std::string subtitle() const override;
protected:
    Node* _root;
    Node* _target;
};

//第三个test,见下图运行效果
class Issue1358 : public BaseTest
{
public:
    CREATE_FUNC(Issue1358);
    virtual bool init();
    void update(float delta);
    virtual std::string subtitle() const override;
protected:
    Vec2 _center;
    float _radius;
    float _angle;
};

#define CL(__className__) [](){ return __className__::create();}//宏定义,new出类,并返回
#define CLN(__className__) [](){ auto obj = new __className__(); obj->autorelease(); return obj; }

//索引,用于判断上一个或下一个
static int sceneIdx = -1;
//函数指针数组
static std::function<Layer*()> createFunctions[] =
{
        CL(MotionStreakTest1),
        CL(MotionStreakTest2),
        CL(Issue1358),
};
//获取数组的大小
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))

//下一个
Layer* nextTest()
{
    sceneIdx++;
    sceneIdx = sceneIdx % MAX_LAYER;//循环判定
    auto layer = (createFunctions[sceneIdx])();//调用函数指针数组中sceneIdx的函数
    //    layer->autorelease();
    return layer;
}
//同上
Layer* prevTest()
{
    sceneIdx--;
    int total = MAX_LAYER;
    if(sceneIdx < 0)
    {
        sceneIdx += total;
    }
    auto layer = (createFunctions[sceneIdx])();
    //    layer->autorelease();
    return layer;
}
//同上
Layer* restartTest()
{
    auto layer = (createFunctions[sceneIdx])();
    //    layer->autorelease();
    return layer;
}

//基类Layer。实现关闭按钮、下一个测试、当前测试、下一个测试菜单项的布局与事件响应
bool BaseTest::init()
{
    bool bRet = true;
    do{
        CC_BREAK_IF(!Layer::init());
        
        Size visibleSize = Director::getInstance()->getVisibleSize();
        Vec2 origin = Director::getInstance()->getVisibleOrigin();
        
        /////////////////////////////
        // 2. add a menu item with "X" image, which is clicked to quit the program
        //    you may modify it.
        
        // add a "close" icon to exit the progress. it's an autorelease object
        auto closeItem = MenuItemImage::create(
                                               "CloseNormal.png",
                                               "CloseSelected.png",
                                               CC_CALLBACK_1(BaseTest::menuCloseCallback, this));
        closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                    origin.y + visibleSize.height - closeItem->getContentSize().height/2));
        
        // create menu, it's an autorelease object
        auto menu1 = Menu::create(closeItem, NULL);
        menu1->setPosition(Vec2::ZERO);
        this->addChild(menu1, 1);
        
        std::string str = title();
        const char * pTitle = str.c_str();
        TTFConfig ttfConfig("tahoma.ttf", 35);
        auto label = Label::createWithTTF(ttfConfig,pTitle);
        addChild(label, 9999);
        label->setPosition( Vec2(VisibleRect::center().x, VisibleRect::top().y - 30) );
        
        std::string strSubtitle = subtitle();
        if( ! strSubtitle.empty() )
        {
            ttfConfig.fontFilePath = "tahoma.ttf";
            ttfConfig.fontSize = 30;
            auto l = Label::createWithTTF(ttfConfig,strSubtitle.c_str());
            addChild(l, 9999);
            l->setPosition( Vec2(VisibleRect::center().x, VisibleRect::top().y - 100) );
        }
        
        auto item1 = MenuItemFont::create("backCallback", CC_CALLBACK_1(BaseTest::backCallback, this) );
        auto item2 = MenuItemFont::create("restartCallback", CC_CALLBACK_1(BaseTest::restartCallback, this) );
        auto item3 = MenuItemFont::create("nextCallback", CC_CALLBACK_1(BaseTest::nextCallback, this) );
        
        auto menu = Menu::create(item1, item2, item3, NULL);
        
        menu->setPosition(Vec2::ZERO);
        item1->setPosition(Vec2(VisibleRect::center().x - item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2));
        item2->setPosition(Vec2(VisibleRect::center().x, VisibleRect::bottom().y+item2->getContentSize().height/2));
        item3->setPosition(Vec2(VisibleRect::center().x + item2->getContentSize().width*2, VisibleRect::bottom().y+item2->getContentSize().height/2));
        
        addChild(menu, 9999);
        
        bRet = true;
    }while(0);
    return bRet;
}

void BaseTest::menuCloseCallback(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
}
//标题
std::string BaseTest::title() const
{
	return "MotionStreak";
}
//副标题
std::string BaseTest::subtitle() const
{
	return "MotionStreak";
}
//重新执行当前test
void BaseTest::restartCallback(Ref* sender)
{
	log("restart!");
    auto s = new MotionStreakDemo();//首先创建一个Scene,然后将当前的test
    s->addChild(restartTest());//Layer加载到当前Scene
    Director::getInstance()->replaceScene(s);//场景切换,第一个场景切换的是HelloWorld中创建的Scene
    s->release();

}
//下一个test
void BaseTest::nextCallback(Ref* sender)
{
	log("next!");
    auto s = new MotionStreakDemo();
    s->addChild(nextTest());
    Director::getInstance()->replaceScene(s);
    s->release();
}
//上一个test
void BaseTest::backCallback(Ref* sender)
{
	log("back!");
    auto s = new MotionStreakDemo();
    s->addChild(prevTest());
    Director::getInstance()->replaceScene(s);
    s->release();
}

void BaseTest::modeCallback(cocos2d::Ref *sender)
{
    bool fastMode = streak->isFastMode();
    streak->setFastMode(!fastMode);
}
bool MotionStreakDemo::init()
{
    bool bRet = false;
    do{
        CC_BREAK_IF(!Scene::init());
        
        auto layer = nextTest();
        addChild(layer);
        
        bRet = true;
    }while(0);
    return bRet;
}

bool MotionStreakTest1::init()
{
    bool bRet = false;
    do{
        CC_BREAK_IF(!BaseTest::init());
        
        auto winSize = Director::getInstance()->getWinSize();
        _root = Sprite::create("r1.png");
        log("_root.x = %lf,_root.y = %lf",_root->getAnchorPoint().x,_root->getAnchorPoint().y);
        _root->setPosition(Vec2(winSize.width/2,winSize.height/2));
        addChild(_root,1);
        
        _target = Sprite::create("r1.png");
        log("_target = %lf,_target.y = %lf",_target->getAnchorPoint().x,_target->getAnchorPoint().y);
        _root->addChild(_target);
        _target->setPosition(Vec2(winSize.width/4,0));
        
        //运动纹理,参数依次为消失时间,最小段,宽度,颜色,纹理图片
        streak = MotionStreak::create(2, 3, 100, Color3B::GREEN, "streak.png");
        addChild(streak);
        schedule(schedule_selector(MotionStreakTest1::onUpdate));
        
        //效果类似地球围绕太阳转的效果
        auto a1 = RotateBy::create(2, 360);
        auto action1 = RepeatForever::create(a1);
        auto motion = MoveBy::create(2, Vec2(100,0));
        _root->runAction(RepeatForever::create(Sequence::create(motion,motion->reverse(), NULL)));
        _root->runAction(action1);
        
        //颜色渐变
        auto colorAction = RepeatForever::create(Sequence::create(
              TintTo::create(0.2f, 255, 0, 0),
              TintTo::create(0.2f, 0, 255, 0),
              TintTo::create(0.2f, 0, 0, 255),
              TintTo::create(0.2f, 0, 255, 255),
              TintTo::create(0.2f, 255, 255, 0),
              TintTo::create(0.2f, 255, 0, 255),
              TintTo::create(0.2f, 255, 255, 255),
              NULL));
        
        streak->runAction(colorAction);
        
        bRet = true;
    }while(0);
    return bRet;
}

void MotionStreakTest1::onUpdate(float delta)
{
    streak->setPosition(_target->convertToWorldSpace(Vec2::ZERO));
    
}

std::string MotionStreakTest1::subtitle() const
{
    return "MotionStreak test 1";
}
//类似画板效果,线条自动消失
bool MotionStreakTest2::init()
{
    bool bRet = false;
    do{
        CC_BREAK_IF(!BaseTest::init());
        //开启多点触摸
        auto listener = EventListenerTouchAllAtOnce::create();
        listener->onTouchesMoved = CC_CALLBACK_2(MotionStreakTest2::onTouchesMoved,this);
        Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
        
        auto winSize = Director::getInstance()->getWinSize();
        streak = MotionStreak::create(3, 3, 64, Color3B::WHITE, "streak.png");
        addChild(streak);
        streak->setPosition(Vec2(winSize.width/2,winSize.height/2));
        
        bRet = true;
    }while(0);
    return bRet;
}

void MotionStreakTest2::onTouchesMoved(const std::vector<Touch *> &touches, cocos2d::Event *event)
{   //根据触摸位置,画线
    auto touchLocation = touches[0]->getLocation();
    streak->setPosition(touchLocation);
}

std::string MotionStreakTest2::subtitle() const
{
    return "MotionStreak test 2";
}
bool Issue1358::init()
{
    bool bRet = false;
    do{
        CC_BREAK_IF(!BaseTest::init());
        
        auto winSize = Director::getInstance()->getWinSize();
        //运动纹理,参数依次为消失时间,最小段,宽度,颜色,纹理图片
        streak = MotionStreak::create(2, 3, 50, Color3B::GREEN, "icon.png");
        addChild(streak);
        _center = Vec2(winSize.width/2,winSize.height/2);
        _radius = winSize.width/3;
        _angle = 0.0f;
        
        //帧间隔0秒,但是推荐使用scheduleUpdate();
        schedule(schedule_selector(Issue1358::update),0);
        
        bRet = true;
    }while(0);
    return bRet;
}

void Issue1358::update(float delta)
{
    _angle += 1.0f;
    streak->setPosition(Vec2(_center.x + cosf(_angle/180*M_PI)*_radius,_center.y+sinf(_angle/180*M_PI)*_radius));
}

std::string Issue1358::subtitle() const
{
    return "MotionStreak test 3";
}


Cocos2d-x3.1TestCpp之MotionStreakTest Demo分析