您的位置:首页 > 移动开发 > Cocos引擎

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

2013-12-10 13:07 274 查看
    在创建按钮的时候,按钮有三个状态: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();

    这样,就能够把一个精灵灰度化了,而且除了灰度,精灵本身没有改变什么。 

    想想看这个功能,还能够使用在什么地方吧——

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: