zoukankan      html  css  js  c++  java
  • 转载+自练(莫喷)怎样在cocos2d 2.1.4里面使用动画和Texture Packer

       本文实践自 Ray Wenderlich、Tony Dahbura 的文章《How to Use Animations and Sprite Sheets in Cocos2D 2.X》,原文链接http://www.raywenderlich.com/32045/how-to-use-animations-and-sprite-sheets-in-cocos2d-2-x 。在这篇文章,将会学习到怎样创建一个简单的熊行走动画,怎样使用精灵表单,怎样改变熊行走的方向等等。

    教程截图:

    让我们首先创建一个project骨架--使用cocos2dproject模板创建一个新的项目并取名为AnimBear.

    接下来,先下载熊行走的图片


    当你解压之后,看看那些图片---它们不过一张张单个的熊在行走的动画帧。可是,当你把它们连续地放映,就会看到一只熊在移动。

    3.下载(点击打开链接Texture Packer工具,当前为3.1.2版本号。拖动资源图片文件到Texture Packer的右边窗体,将会自己主动载入文件。左边窗体中的Geometry面板,调整Max size为4096x4096,由于默认尺寸不够满足大小。Layout面板,设置Trim mode为None,不须要移除透明像素。完毕之后,例如以下图所看到的:

    在”Resources“文件夹下新建文件夹”HDR“。确定Output面板中Data Format选中cocos2dData filename定位到”...AnimBearResourcesHDR“路径,文件名称为AnimBear.plist。保存之后,Texture file将会自己主动填充文件名称。然后,点击AutoSD设置button,下拉选择Presets项为”cocos2d-x HDR/HD/SD“,点击”Apply“button,这使得在公布时可以自己主动创建和保存多种规则的精灵表单,例如以下图所看到的:

    最后,点击工具栏button”Publish“,将会自己主动生成精灵表单和纹理文件,例如以下图所看到的:

    能够用plist Editor Pro打开AnimBear.plist文件,能够看到它由两部分组成——帧和元数据。在帧部分,每个图像都有一个属性,用来描写叙述位于精灵表单中的包围框。例如以下图所看到的:

    3.一个简单的动画。打开HelloWorldScene.h文件,加入例如以下代码:

    1
    2
    3
    4
    5
    6
        CC_SYNTHESIZE_RETAIN(cocos2d::CCSprite*, _bear, Bear);
        CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _walkAction, WalkAction);
        CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _moveAction, MoveAction);

    private:
        bool _bearMoving;
     
    在HelloWorldScene.h加入构造函数:
    Helloworld();
     
    打开HelloWorldScene.cpp文件,新建构造函数,在构造函数里面,加入例如以下代码:
    1
    2
    3
    4
    5
    6
    7
    HelloWorld::HelloWorld()
    {
        _bear = NULL;
        _walkAction = NULL;
        _moveAction = NULL;
        _bearMoving = false;
    }
    改动init函数,为例如以下代码: 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    bool HelloWorld::init()
    {
        bool bRet = false;
        do
        {
            CC_BREAK_IF(!CCLayer::init());
           
            //1) Cache the sprite frames and texture
            CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("AnimBear.plist");

            //2) Create a sprite batch node
            CCSpriteBatchNode *spriteSheet = CCSpriteBatchNode::create("AnimBear.png");
            this->addChild(spriteSheet);

            //3) Gather the list of frames
            CCArray *walkAnimFrames = CCArray::create();
            for (int i =1; i <=8; ++i)
            {
                walkAnimFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(
                    CCString::createWithFormat("bear%d.png", i)->getCString()));
            }
           
            //4) Create the animation object
            CCAnimation *walkAnim = CCAnimation::createWithSpriteFrames(walkAnimFrames,0.1f);

            //5) Create the sprite and run the animation action
            CCSize winSize = CCDirector::sharedDirector()->getWinSize();
            this->setBear(CCSprite::createWithSpriteFrameName("bear1.png"));
            this->getBear()->setPosition(ccp(winSize.width /2, winSize.height /2));
            this->setWalkAction(CCRepeatForever::create(CCAnimate::create(walkAnim)));
            this->getBear()->runAction(this->getWalkAction());
            spriteSheet->addChild(this->getBear());

            bRet = true;
        } while (0);
        return bRet;
    }
    以上各个步骤说明例如以下:
    ①.缓存精灵帧和纹理。调用CCSpriteFrameCache的addSpriteFramesWithFile方法,传入之前生成的属性列表文件名。这种方法做了例如以下事情:
    • 从属性列表文件的元数据部分,取出textureFileName的值,作为纹理文件的文件名称,在这里为AnimBear.png,加载文件到CCTextureCache纹理缓存中。注意,这里会依据设定的资源搜索路径来自己主动寻找正确的文件。
    • 解析属性列表文件,使用CCSpriteFrame对象来内部地跟踪全部精灵的信息。
    ②.创建一个精灵批处理节点。创建CCSpriteBatchNode对象,传入了精灵表单图像名称。精灵表单的工作方式例如以下:
    • 创建CCSpriteBatchNode对象,传入包括全部精灵的图像文件的名称,将这个对象加入到场景里面。
    • 如今,不论什么时候创建来自这个精灵表单的精灵,都应当将这个精灵加入到这个CCSpriteBatchNode对象里。仅仅要精灵是来自这个精灵表单的,那么就会正常工作,否则会报错。
    • CCSpriteBatchNode代码智能地将CCSprite孩子对象在一次的OpenGL ES调用中进行绘制,而不是多次调用,而这会使得速度快得多。
    ③.採集帧列表。为了创建帧列表,须要简单地遍历图片的名称(它们被命名为Bear1.png -> Bear8.png,这是一个惯例),然后,从CCSpriteFrameCache里寻找指定名称的精灵帧。请记住,这些应该已经在缓存中,由于之前调用了addSpriteFramesWithFile方法。
    ④.创建动画对象。通过传入精灵帧列表,创建CCAnimation对象,并指定动画的播放速度。这里使用0.1秒作为帧之间的延迟时间。
    ⑤.创建精灵和执行动画动作。以某一帧来创建精灵(即熊),放置在屏幕中心。传入CCAnimation对象,创建CCAnimate对象,并让熊执行这个动作。最后,将熊加入到精灵表单里。注意,假设没有加入到精灵表单里,而是加入到层里的话,就不会得到性能的优化。
    为了能在不同分辨率下,载入不同的资源,须要先设置下分辨率适配,打开AppDelegate.cpp文件,在applicationDidFinishLaunching函数里面,最上面代码改动为:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();
    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());

    CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();

    CCSize designSize = CCSizeMake(480, 320);
    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionNoBorder);
    CCSize frameSize = CCEGLView::sharedOpenGLView()->getFrameSize();
    CCSize resourceSize;
    std::vector<std::string> searchPath;
    if (frameSize.height > 768)
    {
        searchPath.push_back("HDR");
        resourceSize = CCSizeMake(2048, 1536);
    }
    else if (frameSize.height >320)
    {
        searchPath.push_back("HD");
        resourceSize = CCSizeMake(1024, 768);
    }
    else
    {
        searchPath.push_back("SD");
        resourceSize = CCSizeMake(480, 320);
    }
    pDirector->setContentScaleFactor(resourceSize.height / designSize.height);
    CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);
    编译执行,能够看到熊愉快地漫步在屏幕上,例如以下图所看到的:

    4.更改熊行走的方向。通过触摸屏幕,来控制熊的移动。打开HelloWorldScene.cpp文件,在init函数里面,凝视掉代码this->getBear()->runAction(this->getWalkAction());,这样一開始熊就不会移动。然后在代码最后加入例如以下代码:

    1
    this->setTouchEnabled(true);
    加入例如以下方法: 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    void HelloWorld::registerWithTouchDispatcher()
    {
        CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,0,true);
    }

    bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
    {
        return true;
    }

    void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
    {
        //1) Determine the touch location
        CCPoint touchLocation = this->convertTouchToNodeSpace(pTouch);

        //2) Set the desired velocity
        CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
        float bearVelocity = screenSize.width / 3.0f;

        //3) Figure out the amount moved in X and Y
        CCPoint moveDifference = ccpSub(touchLocation, this->getBear()->getPosition());

        //4) Figure out the actual length moved
        float distanceToMove = ccpLength(moveDifference);

        //5) Figure out how long it will take to move
        float moveDuration = distanceToMove / bearVelocity;

        //6) Flip the animation if necessary
        if (moveDifference.x < 0)
        {
            this->getBear()->setFlipX(false);
        }
        else
        {
            this->getBear()->setFlipX(true);
        }
       
        //7) Run the appropriate actions
        this->getBear()->stopAction(this->getMoveAction());

        if (!_bearMoving)
        {
            this->getBear()->runAction(this->getWalkAction());
        }
       
        this->setMoveAction(CCSequence::create(
            CCMoveTo::create(moveDuration, touchLocation),
            CCCallFunc::create(this, callfunc_selector(HelloWorld::bearMoveEnded)),
            NULL));

        this->getBear()->runAction(this->getMoveAction());
        _bearMoving = true;
    }

    void HelloWorld::cleanup()
    {
        CC_SAFE_RELEASE_NULL(_moveAction);
        CCLayer::cleanup();
    }

    void HelloWorld::bearMoveEnded()
    {
        this->getBear()->stopAction(this->getWalkAction());
        _bearMoving = false;
    }
    bearMoveEnded方法被调用时,不再移动,停止动画。ccTouchEnded方法说明例如以下:
    • ①确定触摸位置。转换触摸点到本地节点坐标。
    • ②设置期望的速度。设置熊的移动速度。
    • ③计算在x轴和y轴上的移动距离。
    • ④计算移动的真实长度。
    • ⑤计算移动的所需时间。
    • ⑥如有必须的话,则翻转动画。通过移动距离的x轴来推断熊是向左还是向右移动。仅仅需设置水平翻转,执行的动画也会跟着翻转。
    • ⑦执行适当的动作。首先,停止现有的移动动作,由于可能半途改变熊的目的地。接着,假设已经在移动了,就继续保持行走动作。最后,创建移动动作,指定移动的位置、移动的时间,和一个动作完毕时的回调,这个回调用来停止行走动作。变量_bearMoving用来推断是否正在移动中。
    编译执行,触摸屏幕来移动熊,例如以下图所看到的:

    參考资料:

    很感谢以上资料,本样例源码附加资源下载地址:http://download.csdn.net/detail/yangshuo528/7411657
    如文章存在错误之处,欢迎指出,以便改正。

  • 相关阅读:
    2016-7-4工作总结
    2016-7第一周工作总结
    2016-6-30 工作总结
    2016-6-29 工作总结
    2016-6-28 工作总结
    基于软件开发对嵌入式开发的思考
    团队项目总结
    软件工程课程总结
    图描述之:流程图
    004-二叉树的遍历
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4309758.html
Copyright © 2011-2022 走看看