cocos2dx:如何将按钮的三张图片节省为一张


    在创建按钮的时候,按钮有三个状态:1、正常;2、被点击;3、不可用。
    最常见的用法是,美术会做三个状态的按钮。 
    但是这样会不会太浪费?
    因为这三个按钮只是颜色上有区别而已,而玩家最常见的其实就是正常和不可用状态下的按钮,而第二种状态的按钮其实并不特别关注。
    cocos2dx里的精灵支持着色上的改变,于是,对于区分要求不是特别高的“被点击”的按钮,就可以用setColor方法来改变。看过精灵类源代码的使用者都能发现这个方法,这个方法很常用。
    示例1:pSpirit->setColor(ccGRAY);//
ccGRAY是引擎预定义的颜色常量。
    示例2: pSpirit->setColor(ccc3(128,128,128));//ccc3是宏,里面的三个参数就是颜色的RBG了,可以自己调试颜色,或者让美术提供参数。
    于是这样就可以节省一个“被点击”的按钮图片了,这通常能够为整个安装包缩减10K以上的体积,积少成多——在所有的地方都这样子节省吧,美术也能减少工作量哦。
    但是,“不可用”的按钮怎么办呢?使用setColor的方法进行实验,发现不管如何设置,都不能达到那种“变灰”的那种味道。
    为了节省资源和人力,其实可以给按钮构造方法的“disabled”参数传入一个NULL,但是这样做的结果就是,这个按钮调用setEnable()方法后,不会出现不可用的状态。
    通过寻找资料,笔者找到一份网友写好的代码,实验之后可以正常使用:
GraySprite.h
//  Created by rekoo on 13-7-23.
#ifndef __goddess__GraySprite__
#define __goddess__GraySprite__
#include "cocos2d.h"
#include "cocos-ext.h"
USING_NS_CC;
USING_NS_CC_EXT;
class  GraySprite :  public  CCSprite
{
public :
     GraySprite();
     ~GraySprite();
                                            
     bool  initWithTexture(CCTexture2D* texture,  const  CCRect&  rect);
     void  draw();
     void  initProgram();
     void  listenBackToForeground(CCObject *obj);
                                            
     static  GraySprite* create( const  char  *pszFileName);
                                            
};
#endif 

GraySprite.cpp
//  Created by rekoo on 13-7-23.
#include "GraySprite.h"
GraySprite::GraySprite()
{
}
GraySprite::~GraySprite()
{
}
GraySprite* GraySprite::create( const  char  *pszFileName)
{
     GraySprite* pRet =  new  GraySprite();
     if  (pRet && pRet->initWithFile(pszFileName))
     {
         pRet->autorelease();
     }
     else
     {
         CC_SAFE_DELETE(pRet);
     }
                                        
     return  pRet;
}
void  GraySprite::listenBackToForeground(CCObject *obj)
{
     setShaderProgram(NULL);
     initProgram();
}
bool  GraySprite::initWithTexture(CCTexture2D* texture,  const  CCRect& rect)
{
     if ( CCSprite::initWithTexture(texture, rect) )
     {
                                                    
         CCSize s = getTexture()->getContentSizeInPixels();
                                         
         this ->initProgram();
                                            
         return  true ;
     }
                                        
     return  false ;
}
void  GraySprite::initProgram()
{
                                        
   const   GLchar * pfrag =    "#ifdef GL_ES \n \
     precision mediump  float ; \n \
     #endif \n\
     uniform sampler2D u_texture; \n \
     varying vec2 v_texCoord; \n \
     varying vec4 v_fragmentColor; \n \
     void  main( void ) \n \
     { \n \
     float  alpha = texture2D(u_texture, v_texCoord).a; \n \
     float  grey = dot(texture2D(u_texture, v_texCoord).rgb, vec3(0.299,0.587,0.114)); \n \
     gl_FragColor = vec4(grey, grey, grey,alpha); \n \
     } ";
                                        
                                     
     CCGLProgram* pProgram =  new  CCGLProgram();
     pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert, pfrag);
     setShaderProgram(pProgram);
     pProgram->release();
                                        
     CHECK_GL_ERROR_DEBUG();
                                        
     getShaderProgram()->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
     getShaderProgram()->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
     getShaderProgram()->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
                                        
     CHECK_GL_ERROR_DEBUG();
                                        
     getShaderProgram()->link();
                                        
     CHECK_GL_ERROR_DEBUG();
                                        
     getShaderProgram()->updateUniforms();
                                        
}
void  GraySprite::draw()
{
     ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex );
     ccBlendFunc blend = getBlendFunc();
     ccGLBlendFunc(blend.src, blend.dst);
                                        
     getShaderProgram()->use();
     getShaderProgram()->setUniformsForBuiltins();
                                        
                                        
     ccGLBindTexture2D( getTexture()->getName());
                                        
#define kQuadSize sizeof(m_sQuad.bl)
     long  offset = ( long )&m_sQuad;
                                        
     int  diff = offsetof( ccV3F_C4B_T2F, vertices);
     glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, ( void *) (offset + diff));
                                        
     diff = offsetof( ccV3F_C4B_T2F, texCoords);
     glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, ( void *)(offset + diff));
                                        
     diff = offsetof( ccV3F_C4B_T2F, colors);
     glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, ( void *)(offset + diff));
                                        
                                        
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
                                        
     CC_INCREMENT_GL_DRAWS(1);
}


    可以看到这个类继承了精灵类,并写了自己的构造方法,还重写了父类的draw方法。
   这个类该怎么使用呢?
    普通的写法就是,把“不可用”状态下的按钮精灵使用这个类进行创建,这样就会是一个灰色的精灵,因为它是精灵类的子类,所以它可以直接用在MenuItem构造方法里的参数里——于是,第三个按钮图片也省下来了。
    但是这个类有局限性,纹理打包技术是cocos2dx里经常会使用到的,很多图片都会使用纹理打包,而这些纹理,它并没有对应的构造方法,有的也是父类的,关键性的initProgram方法没法调用到。
    那么,我们有几个方案:
        方案1、修改这个类,让它重写精灵类的各种构造初始化方法;
        方案2、类型转换。
    方案1的工作量有些大,几乎把精灵类重新写了一遍,说不定还是直接去修改精灵类源码比较好。
    然后我们来看看方案2:
    示例:
    ((GraySprite*)pSprite)->initProgram();
    这样,就能够把一个精灵灰度化了,而且除了灰度,精灵本身没有改变什么。 
    想想看这个功能,还能够使用在什么地方吧——


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值