zoukankan      html  css  js  c++  java
  • cocos2d-x开发记录:二,基本概念(动作,动画,坐标系统)

    既然我们选择用cocos2d,那么他里面的一些基本概念我们肯定是要熟悉下的,以下资料来源于官网,英语好的可以直接去官网看。

    一.Actions(动作)

    动作都由于CCNode对象发出。这些动作通常修改对象的一些属性,比如位置,旋转,比例等。如果这些属性在某一个时间周期内被修改,那么它们是CCIntervalAction动作。否则它们是CCInstantAction动作。例如CCMoveBy动作在某段时间内修改了位置属性,因此,它是CCIntervalAction的子类。我们能运行TestCpp->Actions来看看动作的可视化效果。这个文件位于cocos2d-x/samples/Cpp/TestCpp/Classes/ActionsTest下。ActionsEaseTest是很好的示例代码用法。

    CCIntervalAction动作有一些有趣的属性:

    它们用于改变动作加速的快慢。你能使用CCActionManager恢复或暂停所有动作。

    // Pause actions
    CCDirector *director = CCDirector::sharedDirector();
    m_pPausedTargets = director->getActionManager()->pauseAllRunningActions();
    // resume actions
    CCDirector *director = CCDirector::sharedDirector();
    director->getActionManager()->resumeTargets(m_pPausedTargets);

    基本动作

    位置

    CCMoveBy
    CCMoveTo
    CCJumpBy
    CCJumpTo
    CCBezierBy
    CCBezierTo
    CCPlace

    比例

    CCScaleBy
    CCScaleTo

    旋转

    CCRotateBy
    CCRotateTo

    可见度

    CCShow
    CCHide
    CCBlink
    CCToggleVisibility

    透明度

    CCFadeIn
    CCFadeOut
    CCFadeTo

    颜色

    CCTintBy
    CCTintTo

    Example:

    CCSprite *sprite = CCSprite::create("Images/grossini.png");
    sprite->setPosition(ccp(100, 100));
    addChild(sprite);
    
    CCMoveBy* act1 = CCMoveBy::create(0.5, ccp(100, 0));
    sprite->runAction(CCRepeat::create(act1, 1));

    二.动画

    帧动画

    你能从一系列的图片文件中创建一个动画,如下所示:

     

    CCAnimation *animation = CCAnimation::create();
    
     
    
     // load image file from local file system to CCSpriteFrame, then add into CCAnimation
    
     for (int i = 1; i < 15; i++)
    
     {
    
         char szImageFileName[128] = {0};
    
         sprintf(szImageFileName, "Images/grossini_dance_%02d.png", i);
    
         animation->addSpriteFrameWithFileName(szImageFileName); 
    
     }
    
     
    
    animation->setDelayPerUnit(2.8f / 14.0f); // This animation contains 14 frames, will continuous 2.8 seconds.
    
    animation->setRestoreOriginalFrame(true); // Return to the 1st frame after the 14th frame is played.
    
     
    
    CCAnimate *action = CCAnimate::create(animation);
    
    sprite->runAction(action);  // run action on sprite object

    注意CCAnimation由精灵(sprite)帧组成。每帧间隔时间,动画持续时间等,这是一个“数据包”。然而CCAnimate是一个动作,它基于CCAnimation对象。

    Sprite Sheet动画

    虽然手动动画是非常容易理解的,但很少用于真正的游戏项目。所以精灵动画是更通用的2D动画解决方案。下图是一个典型的Sprite Sheet。它可以是一个序列帧动画,或者是一个图片包被用在同一场景中。

    在 OpenGL ES 1.1时期,sprite sheets被广泛用于以下这些福利:

    ◆减少文件IO时间,载入一个大的sprite sheet文件跟载入大量小的文件整体速度更快。

    ◆减少内存消耗。OpenGL ES 1.1仅能用于纹理的2次方大小。(2,4,8,64,128,256,512,1024等)。换句话说,OpenGL ES 1.1分配2次方大小的内存给每一个纹理,即使这个纹理小于分配的宽高。因此使用sprite sheet包裹在一起的图片将会减少内存碎片。

    ◆减少OpenGL ES 绘制方法的调用并加速渲染。

    Cocos2d-x v2.0升级到了OpenGL ES 2.0。OpenGL ES 2.0不再分配2次方纹理大小了。但减少文件IO和绘制调用的福利仍然有效。那么怎么样关联动画?正如我们所见,sprite sheet没有和动画有必然会发生的关系。但考虑到以上这些福利,sprite sheet动画是有效率的。在cocos2d中有不同的方法来创建sprite sheet动画。

    从.png和 .plist文件中创建

    在cocos2d-x 0.x和1.x 版本中,CCSpriteSheet是用于这个目的。然而 自从v2.0开始CCSpriteBatchNode已经替代了CCSpriteSheet。

    一个CCSpriteBatchNode对象包含所有精灵帧的实际图像纹理。你必须添加它到场景中。即使它不会绘制它自己。但它只需要一部分的渲染管道。例如:

    CCSpriteBatchNode* spritebatch = CCSpriteBatchNode::create("animations/grossini.png");

    下一步,你需要使用CCSpriteFrameCache单例来跟踪帧名和宽高。下面是prite sheet的矩形区域,例如:

    CCSpriteFrameCache* cache =  CCSpriteFrameCache::sharedSpriteFrameCache();
    cache->addSpriteFramesWithFile("animations/grossini.plist");

    一旦你的sprite sheet和帧被载入,并且sprite sheet被添加到场景中,你能使用“createWithSpriteFrameName”方法来创建精灵用于这些帧数中,并作为一个孩子把这个Sprite添加到batch中:

    m_pSprite1 = CCSprite::createWithSpriteFrameName("grossini_dance_01.png");
    spritebatch->addChild(m_pSprite1);
    addChild(spritebatch);

    createWithSpriteFrameName方法会从grossini.plist中找到正确的坐标和矩形,然后裁切纹理到一个精灵帧中。现在我们需要创建一个CCArray对象并添加所有动画帧到它里面去。对于这个动画,我们知道所有14帧有同样的尺寸,因此我们可以用一个循环遍历它们,当添加到第14帧的时候跳出循环。

     CCArray* animFrames = CCArray::createWithCapacity(15);
    
     char str[100] = {0};
    
     for(int i = 1; i < 15; i++)
     {
    
         sprintf(str, "grossini_dance_%02d.png", i);
    
         CCSpriteFrame* frame = cache->spriteFrameByName( str );
    
         animFrames->addObject(frame);
    
    }

    最后,我们需要创建一个CCAnimate动作实例,我们可以在CCSprite 执行。我们也把CCAnimate动作包裹到CCRepeatForever 动作里,然后你想要的就是永远重复这个动画:

    CCAnimation* animation = CCAnimation::createWithSpriteFrames(animFrames, 0.3f);
    
    m_pSprite1->runAction( CCRepeatForever::create( CCAnimate::create(animation) ) );

    文件动画

    CCAnimationCache 能载入xml/plist文件,很好的描述了批处理节点,精灵帧名字和它们的矩形。接口更容易使用

    CCAnimationCache *cache = CCAnimationCache::sharedAnimationCache(); // "caches" are always singletons in cocos2d
    
    cache->addAnimationsWithFile("animations/animations-2.plist");
    
    CCAnimation animation = cache->animationByName("dance_1");  // I apologize for this method name, it should be getAnimationByName(..) in future versions
    
    CCAnimate animate = CCAnimate::create(animation);  // Don't confused between CCAnimation and CCAnimate :)
    
    sprite->runAction(animate);

    三.坐标系统

    不同坐标系统的介绍

    1.笛卡尔坐标系统

    你在学校的时候可能知道笛卡尔坐标系统它大量用于几何课程中。如果你已经忘记了,下面这些图片会让你马上回想起来:

    在手机游戏开发中,你会遇到3种坐标系统

    2.UI坐标系统

    UI坐标系在iOS/Android/Windows SDK中常见:

    原点(x=0,y=0)在左上角。

    X轴从屏幕的左边往右边增加。

    Y轴从屏幕的顶部往底部增加。

    如下所示:

    3.Direct3D坐标系统

    DirectX使用的是左手笛卡尔坐标系统。

    4.OpenGL和Cocos2d坐标系统

    Cocos2d-x/-html5/-iphone和OpenGL一样使用同样的坐标系统,它被叫做右手笛卡尔坐标系

     

    在2D世界中,我们仅使用X轴和Y轴。因此在你的cocos2d游戏中:

    原点(x=0, y=0)在屏幕左下方,这意味着屏幕在右手笛卡尔坐标系的第一象限

    X轴从屏幕的左边往右边增加。

    Y轴从屏幕的底部往顶部增加。

    下图更直接的解释了cocos2d-x的坐标系:

    注意它不同于常见的UI坐标系和DirectX 坐标系

    父类于子类

    每个类都是CCNode(这是cocos2d-x的最基类,就像java中的Object一样)的子类,并且都有一个anchorPoint(锚点)属性。当确定绘制对象的位置时,cocos2d-x将联合position和anchorPoint属性。当旋转对象时,cocos2d-x也会根据此锚点旋转。我们创建一个父类(灰色)精灵和一个子类(蓝色)精灵。并且父类的位置为cpp(100,100),子类的锚点设置为中心,代码如下所示:

       

      CCSprite* parent = CCSprite::create("parent.png");
    
         parent->setAnchorPoint(ccp(0, 0));// Anchor Point
    
         parent->setPosition(ccp(100, 100));
    
         parent->setAnchorPoint(ccp(0, 0));
    
         addChild(parent);
    
     
    
         //create child
    
         CCSprite* child = CCSprite::create("child.png");
    
         child->setAnchorPoint(ccp(0.5, 0.5));
    
         child->setPosition(ccp(0, 0));
    
         parent->addChild(child);//add child sprite into parent sprite.

    虽然我们设置子类的cpp(0,0),但父类的位置为cpp(100,100),因此运行后效果图,如下所示:

    锚点

    锚点被用于位置和旋转中。锚点坐标是相对坐标,通常对应于对象中的一个点。例如,锚点cpp(0.5,0.5)对应于对象的中心。当设置对象的位置时,setPosition()方法内部会调用锚点。旋转也是如此。例如,下面是一个精灵,它的锚点为cpp(0,0)并且位置为cpp(0,0);

     

    代码如下所示:

    // create sprite
    
    CCSprite* sprite = CCSprite::create("bottomleft.png");
    
    sprite->setAnchorPoint(ccp(0, 0));// Anchor Point
    
    sprite->setPosition(ccp(0,0));
    
    addChild(sprite);

    运行后的效果如下所示:

    如果锚点想设置为精灵的中心,则使用ccp(0.5, 0.5),代码如下所示:

     

    // create sprite
    
    CCSprite* sprite = CCSprite::create("center.png");
    
    sprite->setAnchorPoint(ccp(0.5, 0.5));// Anchor Point
    
    sprite->setPosition(ccp(0,0));
    
    addChild(sprite);

    运行后的效果如下:

    getVisibleSize, getVisibleOrigin vs getWinSize

    VisibleSize返回OpenGL视图中的可见大小。如果不调用CCEGLView::setDesignResolutionSize()的情况下它的值等于getWinSize
    getVisibleOrigin返回可见的OpeaGL视图中的原点。更多细节可以参考官网的Multi resolution support

    怎么转换到co坐标系

    1.convertToNodeSpace(转换到节点空间):

    convertToNodeSpace将被用于有一个大地图的骰牌游戏。convertToNodeSpace 将转换你的openGL触摸co-坐标到.tmx地图中或其他相似的文件中。例如:以下图片显示了2个节点。node1的锚点为(0,0),node2的锚点为(1,1)。

    我们调用CCPoint point = node1->convertToNodeSpace(node2->getPosition()); 转换 node2的屏幕坐标到node1的本地坐标。node2的位置为(-25,-60),如下图所示 :

    2.convertToWorldSpace(转换到世界空间):

    convertToWorldSpace(const CCPoint& nodePoint) 

    转换节点坐标到屏幕坐标。convertToWorldSpace将一直返回屏幕坐标,如果你想要在精灵上捕捉信号,但需要移动/缩放你的layer时,这个方法可能很有用。通常父节点通过子节点的位置调用这个方法,返回子节点的世界位置作为结果。如果调用者不是父节点,那么调用这个方法似乎毫无含义。

    例如:

    CCPoint point = node1->convertToWorldSpace(node2->getPosition());

    上面的代码将转换节点2的坐标到屏幕坐标中。例如如果节点2的位置是(0,0),它在节点1的左下方,它不一定在屏幕上。节点2在屏幕的位置将被转换为(0,0),在本例中为(15,20),如下图所示:

     

    3.convertToWorldSpaceAR(相对于锚点转换)

    convertToWorldSpaceAR将返回相对于锚点的位置:如果我们的场景根节点layer的锚点为cpp(0.5f,0.5f)这是默认的。convertToWorldSpaceAR 将返回相对于屏幕中心的位置

    convertToNodeSpaceAR逻辑和convertToWorldSpaceAR一样,如下面代码所示:

     

     CCSprite *sprite1 = CCSprite::create("CloseNormal.png");
    
     sprite1->setPosition(ccp(20,40));
    
     sprite1->setAnchorPoint(ccp(0,0));
    
     this->addChild(sprite1);
    
    CCSprite *sprite2 = CCSprite::create("CloseNormal.png");
    
    sprite2->setPosition(ccp(-5,-20));
    
    sprite2->setAnchorPoint(ccp(1,1));
    
    this->addChild(sprite2);
    
    CCPoint point1 = sprite1->convertToNodeSpace(sprite2->getPosition());
    
    CCPoint point2 = sprite1->convertToWorldSpace(sprite2->getPosition());
    
    CCPoint point3 = sprite1->convertToNodeSpaceAR(sprite2->getPosition());
    
    CCPoint point4 = sprite1->convertToWorldSpaceAR(sprite2->getPosition());
    
    CCLog("position = (%f,%f)",point1.x,point1.y);
    
    CCLog("position = (%f,%f)",point2.x,point2.y);
    
    CCLog("position = (%f,%f)",point3.x,point3.y);
    
    CCLog("position = (%f,%f)",point4.x,point4.y);

     

    结果为:

     position = (-25.000000,-60.000000)

     position = (15.000000,20.000000)

     position = (-25.000000,-60.000000)

     position = (15.000000,20.000000)

  • 相关阅读:
    4-10
    4-9
    第三章例3-4
    第三章例3-3
    第三章例3-2
    第三章例3-1
    第二章例2-11
    第二章例2-10
    第二章例2-9
    第二章例2-8
  • 原文地址:https://www.cnblogs.com/tianjian/p/3359164.html
Copyright © 2011-2022 走看看