转自:http://www.cocos2dev.com/?p=295

前段时间看CCEditBox的时候,发现里面有个利用9宫格图缩放图片的,也就是缩放带圆角的图片。

这个比较有用处,很多游戏中有很多不同尺寸的圆角图片作为背景。有了CCScale9Sprite之后,只需要提供一个非常小尺寸的圆角图片就可以自由缩放其他尺寸的圆角图。是个不错的东西。

使用方法:

1、导入头文件及命名空间

  1. #include cocos-ext.h
  2. USING_NS_CC_EXT;

2、初始化代码:

  1. CCScale9Sprite* labBg1 = CCScale9Sprite::create(“wd_bg_text.png”);
  2. labBg1->setAnchorPoint(ccp(.,.));
  3. labBg1->setPreferredSize(CCSizeMake(, ));
  4. labBg1->setPosition(ccp(size.width/, size.height/));
  5. addChild(labBg1);

说明:

setPreferredSize 就是设置需要生成的尺寸大小。

看效果:

扩展:转自:http://blog.csdn.net/onerain88/article/details/8273219

cocos2d 2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图片资源的中间部分是纯色或者是简单的渐变了!

1.cocos2d中九宫格CCScale9Sprite的实现

(1)原理

cocos2d的实现非常巧妙,是通过1个CCSpriteBatchNode和9个CCSprite来实现的,原理很简单,通过将原纹理资源切割成9部分(PS: 这也是叫九宫格的原因),根据想要的尺寸,完成以下的三个步骤:

a. 保持4个角部分不变形

b. 单向拉伸4条边(即在4个角两两之间的边,比如上边,只做横向拉伸)

c. 双向拉伸中间部分(即九宫格的中间部分,横向,纵向同时拉伸,PS:拉伸比例不一定相同)

(PS: 更多原理可参考 http://yannickloriot.com/2011/12/create-buttons-in-cocos2d-by-using-cccontrolbutton/

(2)实现

CCSpriteBatchNode的资源为整个的纹理,9个CCSprite对应于纹理的9个部分(根据纹理不同,9部分所占比例会有所不同),根据想要的尺寸,将9部分拼装在一起!

(3)优缺点

优点:思路简单清晰;使用CCSpriteBatchNode,只需要一次绘制,效率较高

缺点:内存占用大,需要1个CCSpriteBatchNode和9个CCSprite对象;不支持CCSpriteBatchNode(如果控件很多,我们都需要对每个控件单独绘制一次,会影响效率)

2.cocos2d-x中CCSprite的绘制

在介绍我的九宫格实现之前,先简单介绍一下CCSprite的绘制原理

(1)顶点数据

每一个CCSprite都保持了一个关于顶点数据的结构体

  1. // vertex coords, texture coords and color info
  2. ccV3F_C4B_T2F_Quad m_sQuad;

这个Quad字眼的意思是一个矩形,参照ccV3F_C4B_T2F_Quad的定义,可以得知,是包含4个顶点数据的结构体(根据注释可知4个顶点分别为:左上,左下,右上,右下)

  1. //! 4 ccVertex3FTex2FColor4B
  2. typedef struct _ccV3F_C4B_T2F_Quad
  3. {
  4. //! top left
  5. ccV3F_C4B_T2F tl;
  6. //! bottom left
  7. ccV3F_C4B_T2F bl;
  8. //! top right
  9. ccV3F_C4B_T2F tr;
  10. //! bottom right
  11. ccV3F_C4B_T2F br;
  12. } ccV3F_C4B_T2F_Quad;

而ccV3F_C4B_T2F又是一个关于顶点信息的结构体,包括坐标(x, y, z),颜色(r, g, b, a),纹理坐标(x, y)

(PS:2D游戏中,坐标的z都为0,这里的z并不是Z-Order,Z-Order是指渲染的先后属性,z是代表3D的z轴坐标)

  1. //! a Point with a vertex point, a tex coord point and a color 4B
  2. typedef struct _ccV3F_C4B_T2F
  3. {
  4. //! vertices (3F)
  5. ccVertex3F vertices; // 12 bytes
  6. // char __padding__[4];
  7.  
  8. //! colors (4B)
  9. ccColor4B colors; // 4 bytes
  10. // char __padding2__[4];
  11.  
  12. // tex coords (2F)
  13. ccTex2F texCoords; // 8 byts
  14. } ccV3F_C4B_T2F;

(2)绘制

在初始化精灵之后,就将纹理的四个顶点信息保存在m_sQuad中了,接下来要做的,就是根据m_sQuad的信息来绘制

由于OpenGL是状态机的设计,所以要先将顶点信息保存,再根据顶点的关系进行绘制,主要的绘制代码如下:

  1. #define kQuadSize sizeof(m_sQuad.bl)
  2. int size = sizeof(m_sQuad.bl);
  3. if (m_pobTexture)
  4. {
  5. glBindTexture(GL_TEXTURE_2D, m_pobTexture->getName());
  6. }
  7. else
  8. {
  9. glBindTexture(GL_TEXTURE_2D, );
  10. }
  11.  
  12. long offset = (long)&m_sQuad;
  13.  
  14. // vertex
  15. int diff = offsetof(ccV3F_C4B_T2F, vertices);
  16. glVertexPointer(, GL_FLOAT, kQuadSize, (void*)(offset + diff));
  17.  
  18. // color
  19. diff = offsetof( ccV3F_C4B_T2F, colors);
  20. glColorPointer(, GL_UNSIGNED_BYTE, kQuadSize, (void*)(offset + diff));
  21.  
  22. // tex coords
  23. diff = offsetof( ccV3F_C4B_T2F, texCoords);
  24. glTexCoordPointer(, GL_FLOAT, kQuadSize, (void*)(offset + diff));
  25.  
  26. glDrawArrays(GL_TRIANGLE_STRIP, , );

(PS: offsetof()函数是得到结构体中某一数据的地址偏移量)

根据注释可知,先将顶点的坐标数据保存,再将顶点的颜色数据保存,最后将顶点的纹理映射坐标保存

(吐槽一下:#define kQuadSize sizeof(m_sQuad.bl) 这个宏的名字把我迷惑了,我不知道为什么会有Quad字眼,我觉得应该是kVertexSize)

3. CCScaleNineSprite的实现

(吐槽一下:我没找到更好的关于九宫格的名字,于是偷懒将9换成了Nine。。。)

我的九宫格的实现和CCScale9Sprite略有不同,只是优化了其内存的问题,我将1个CCSpriteBatchNode和9个CCSprite用1个CCSprite来实现了,通过纹理映射做拉伸!

(PS:我目前也没有解决支持CCSpriteBatchNode,因为CCSpriteBatchNode的子节点要求是CCSprite类型,而我的CCScaleNineSprite并不是继承于CCSprite,而是于CCSprite是兄弟关系,因为其顶点的数据不同,所以我认为不是继承关系,当然可以考虑把CCSprite的顶点数据修改,使其不再被限制于固定4个顶点)

我偷懒将CCSprite.h和CCSprite.cpp拷贝了一份,注释掉了一些不常用的方法,以及对CCSpriteBatchNode的支持。。。

将m_sQuad替换为ccV3F_C4B_T2F mScaleNineVertices[16](九宫格需要16个顶点,请根据上面的图计算,包括顶点和切割线的交点)

额外增加了1个设置九宫格比例的方法(重载了3份),通过比例计算出mScaleNineVertices的数据

  1. public:
  2. void CalculateScaleNineVertices(unsigned int widthFromLeft, unsigned int widthFromRight,
  3. unsigned int heightFromTop, unsigned int heightFromBottom);
  4. void CalculateScaleNineVertices(unsigned int widthFromLeft, unsigned int heightFromTop);
  5. void CalculateScaleNineVertices(unsigned int offsetFromEdge);

贴上这个长长的计算算法吧,我表示我很笨,没有想到更好的计算算法。。。欢迎留言赐教

  1. void CCScaleNineSprite::CalculateScaleNineVertices(unsigned int widthFromLeft, unsigned int widthFromRight,
  2. unsigned int heightFromTop, unsigned int heightFromBottom)
  3. {
  4. float textureOriginX = m_obRectInPixels.origin.x;
  5. float textureOriginY = m_obRectInPixels.origin.y;
  6.  
  7. float textureWidth = m_obRectInPixels.size.width;
  8. float textureHeight = m_obRectInPixels.size.height;
  9.  
  10. CCAssert((widthFromLeft < textureWidth) && (widthFromRight < textureWidth) &&
  11. (heightFromTop < textureHeight) && (heightFromBottom < textureHeight), "The SIZE of Corner is too BIG!");
  12.  
  13. float contentWidth = m_tContentSizeInPixels.width;
  14. float contentHeight = m_tContentSizeInPixels.height;
  15.  
  16. unsigned int textureAtlasWidth = getTexture()->getPixelsWide();
  17. unsigned int textureAtlasHeight = getTexture()->getPixelsHigh();
  18.  
  19. ccV3F_C4B_T2F vertice;
  20.  
  21. // First Line
  22. vertice.vertices.x = ;
  23. vertice.vertices.y = contentHeight;
  24. vertice.vertices.z = ;
  25. vertice.colors.a = ;
  26. vertice.colors.r = ;
  27. vertice.colors.g = ;
  28. vertice.colors.b = ;
  29. vertice.texCoords.u = textureOriginX / textureAtlasWidth;
  30. vertice.texCoords.v = textureOriginY / textureAtlasHeight;
  31. mScaleNineVertices[] = vertice;
  32.  
  33. vertice.vertices.x = (float) widthFromLeft;
  34. vertice.texCoords.u = (float) (textureOriginX + widthFromLeft) / textureAtlasWidth;
  35. mScaleNineVertices[] = vertice;
  36.  
  37. vertice.vertices.x = (float) (contentWidth - widthFromRight);
  38. vertice.texCoords.u = (float) (textureOriginX + textureWidth - widthFromRight) / textureAtlasWidth;
  39. mScaleNineVertices[] = vertice;
  40.  
  41. vertice.vertices.x = (float) contentWidth;
  42. vertice.texCoords.u = (float) (textureOriginX + textureWidth) / textureAtlasWidth;
  43. mScaleNineVertices[] = vertice;
  44.  
  45. // Second Line
  46. vertice.vertices.x = ;
  47. vertice.vertices.y = (float) (contentHeight - heightFromTop);
  48. vertice.texCoords.u = textureOriginX / textureAtlasWidth;
  49. vertice.texCoords.v = (float) (textureOriginY + heightFromTop) / textureAtlasHeight;
  50. mScaleNineVertices[] = vertice;
  51.  
  52. vertice.vertices.x = (float) widthFromLeft;
  53. vertice.texCoords.u = (float) (textureOriginX + widthFromLeft) / textureAtlasWidth;
  54. mScaleNineVertices[] = vertice;
  55.  
  56. vertice.vertices.x = (float) (contentWidth - widthFromRight);
  57. vertice.texCoords.u = (float) (textureOriginX + textureWidth - widthFromRight) / textureAtlasWidth;
  58. mScaleNineVertices[] = vertice;
  59.  
  60. vertice.vertices.x = (float) contentWidth;
  61. vertice.texCoords.u = (float) (textureOriginX + textureWidth) / textureAtlasWidth;
  62. mScaleNineVertices[] = vertice;
  63.  
  64. // Third Line
  65. vertice.vertices.x = ;
  66. vertice.vertices.y = (float) heightFromBottom;
  67. vertice.texCoords.u = textureOriginX / textureAtlasWidth;
  68. vertice.texCoords.v = (float) (textureOriginY + textureHeight - heightFromBottom) / textureAtlasHeight;
  69. mScaleNineVertices[] = vertice;
  70.  
  71. vertice.vertices.x = (float) widthFromLeft;
  72. vertice.texCoords.u = (float) (textureOriginX + widthFromLeft) / textureAtlasWidth;
  73. mScaleNineVertices[] = vertice;
  74.  
  75. vertice.vertices.x = (float) (contentWidth - widthFromRight);
  76. vertice.texCoords.u = (float) (textureOriginX + textureWidth - widthFromRight) / textureAtlasWidth;
  77. mScaleNineVertices[] = vertice;
  78.  
  79. vertice.vertices.x = (float) contentWidth;
  80. vertice.texCoords.u = (float) (textureOriginX + textureWidth) / textureAtlasWidth;
  81. mScaleNineVertices[] = vertice;
  82.  
  83. // Fourth Line
  84. vertice.vertices.x = ;
  85. vertice.vertices.y = ;
  86. vertice.texCoords.u = textureOriginX / textureAtlasWidth;
  87. vertice.texCoords.v = (float) (textureOriginY + textureHeight) / textureAtlasHeight;
  88. mScaleNineVertices[] = vertice;
  89.  
  90. vertice.vertices.x = (float) widthFromLeft;
  91. vertice.texCoords.u = (float) (textureOriginX + widthFromLeft) / textureAtlasWidth;
  92. mScaleNineVertices[] = vertice;
  93.  
  94. vertice.vertices.x = (float) (contentWidth - widthFromRight);
  95. vertice.texCoords.u = (float) (textureOriginX + textureWidth - widthFromRight) / textureAtlasWidth;
  96. mScaleNineVertices[] = vertice;
  97.  
  98. vertice.vertices.x = (float) contentWidth;
  99. vertice.texCoords.u = (float) (textureOriginX + textureWidth) / textureAtlasWidth;
  100. mScaleNineVertices[] = vertice;
  101. }

计算好顶点数据之后,简单修改一下draw()函数就可以了(将之前的m_sQuad替换为mScaleNineVertices)

  1. #define kVertexSize sizeof(ccV3F_C4B_T2F)
  2. if (m_pobTexture)
  3. {
  4. glBindTexture(GL_TEXTURE_2D, m_pobTexture->getName());
  5. }
  6. else
  7. {
  8. glBindTexture(GL_TEXTURE_2D, );
  9. }
  10.  
  11. // vertex
  12. int diff = offsetof(ccV3F_C4B_T2F, vertices);
  13. glVertexPointer(, GL_FLOAT, kVertexSize, (void*)(offset + diff));
  14.  
  15. // color
  16. diff = offsetof( ccV3F_C4B_T2F, colors);
  17. glColorPointer(, GL_UNSIGNED_BYTE, kVertexSize, (void*)(offset + diff));
  18.  
  19. // tex coords
  20. diff = offsetof( ccV3F_C4B_T2F, texCoords);
  21. glTexCoordPointer(, GL_FLOAT, kVertexSize, (void*)(offset + diff));
  22. glDrawElements(GL_TRIANGLES, , GL_UNSIGNED_SHORT, mVerticesIndex);

看起来和之前的差别不大。。。只有两处修改(高亮吧!)

4.Demo

和CCSprite的使用差不太多,只是需要设置一下ContentSize(即展示的尺寸),并且需要设置九宫格切割的比例(以像素为单位,美术比较好理解!)

  1. CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage("GreenButton.png");
  2. CCScaleNineSprite* scaleNineSprite = CCScaleNineSprite::scaleNineSpriteWithTexture(texture);
  3. scaleNineSprite->setContentSize(CCSizeMake(, ));
  4. scaleNineSprite->CalculateScaleNineVertices();
  5. scaleNineSprite->setPosition(CCPointMake(size.width / , size.height / ));
  6. this->addChild(scaleNineSprite);

效果如下:

原资源

cocos2d-x CCScale9Sprite的更多相关文章

  1. GUI之CCControlExtension

    Introduction CCControl is inspired by the UIControl API class from the UIKit library of CocoaTouch. ...

  2. 学生信息管理系统(cocos2d引擎)——数据结构课程设计

    老师手把手教了两天半,看了一下模式,加了几个功能就大功告成了!!! 给我的感想就是全都是指针! 添加图片精灵: CCSprite*  spBG = CCSprite::create("&qu ...

  3. cocos2d-x中CCScale9Sprite的另一种实现

    cocos2d 2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观 ...

  4. 1cocos2dx扩展UI控制,CCControlSlider,CCScale9Sprite(九妹图。),CCControlSwitch,CCControlButton

     UI控件来自cocos2dx的扩展库.完好了UI方面的元素,使cocos2dx更加丰富多彩.使用扩展库需包括: #include "cocos-ext.h" USING_NS ...

  5. 【转】CCScale9Sprite和CCControlButton

    转自:http://blog.csdn.net/nat_myron/article/details/12975145 在2dx下用到了android下的.9.png图片,下面是原图   查了一下2dx ...

  6. cocos2dx基础篇(11) 点九图CCScale9Sprite

    [3.x] (1)去掉"CC" [v3.3] 我们在 ui模块 下实现了一个新的Scale9Sprite类.它的内部实现比之前的Scale9Sprite更为简洁,功能也更为强大. ...

  7. 小尝试一下 cocos2d

    好奇 cocos2d 到底是怎样一个框架,正好有个项目需要一个游戏框架,所以稍微了解了一下.小结一下了解到的情况. 基本概念 首先呢,因为 cocos2d 是基于 pyglet 做的,你完全可以直接用 ...

  8. 采用cocos2d-x lua 制作数字滚动效果样例

    require "Cocos2d"require "Cocos2dConstants"local testscene = class("testsce ...

  9. Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板

    很久没有写博客了,这段时间比较忙,又是搬家又是做自己的项目,还有太多琐碎的事情缠身,好不容易抽出时间把最近自己做的一些简单例子记录一下. 在我的项目中,我需要一个显示面板来显示游戏中的一个三维数据,例 ...

随机推荐

  1. OK335xS dhcpcd porting

    /********************************************************************** * OK335xS dhcpcd porting * 说 ...

  2. LeetCode: Single Number I && II

    I title: Given an array of integers, every element appears twice except for one. Find that single on ...

  3. vc2005编译ffmpeg以及ffplay

    ffmpeg编译过程:1 http://ffmpeg.zeranoe.com/builds/下载官方提供的源码,win32库和dll.2 新建vc2005 console空工程,把ffmpeg.h,f ...

  4. VS2010下编译安装DarwinStreamingServer5.5.5

    源码下载链接:http://dss.macosforge.org/源码版本: 5.5.5版本电脑环境:visual studio2010,window 7 x64系统.用VS2010打开WinNTSu ...

  5. WdatePicker的一些用法

    在选择日期之后,再执行自己的另一个函数   onpicked: function () { LoadData(); }  <input type="text" class=& ...

  6. solr4.5 schema.xml配置文件

    schema.xml配置文件是用于定义index索引库的结构,有点类似于数据表表的定义. 当我们打开schema.xml配置文件时,也许会被里面密密麻麻的代码所吓倒,其实不必惊慌,里面其实就两个东西f ...

  7. Hibernate管理Session和批量操作

    Hibernate管理Session Hibernate自身提供了三种管理Session对象的方法 Session对象的生命周期与本地线程绑定 Session对象的生命周期与JTA事务绑定 Hiber ...

  8. 按钮点击WIN8 磁贴效果

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  9. Python 学习笔记(三)Function

    python引用变量的顺序: 当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量 1. Scope: • If a variable is assi ...

  10. CSS Sprite的优缺点分析

    目前大多数的开发人员对这个技术都有相当地掌握,也有很多关于它的教程和文章.几乎所有的文章中都宣称设计师和开发人员都应该使用 CSS sprite 来减少 HTTP 请求数,并且节省一些流量.这个技术被 ...