关于 2dx v3.7 UIScale9Sprite的bug
2015-08-28 13:25
543 查看
关于 2dx v3.7 UIScale9Sprite的bug
刚把引擎从js binding v3.0升级到v3.7,发现了一些bug,这里先说说关于scale9sprite的1. 关于capInsets
https://github.com/cocos2d/cocos2d-x/issues/13560问题描述:使用cocosbuilder创建的九宫格图片,如果capInserts没有设置(即ZERO),那么九宫格使用的应该是默认缩放,但是结果却是没有缩放。
builder中:
运行结果(上图使用builder默认inserts产生的错误九宫格,下图正常九宫格缩放):
解决方案:
bool Scale9Sprite::updateWithSprite(Sprite* sprite, const Rect& textureRect, bool rotated, const Vec2 &offset, const Size &originalSize, const Rect& capInsets) { //... // Set the given rect's size as original size _spriteRect = rect; _offset = offset; _spriteFrameRotated = rotated; _originalSize = size; _preferredSize = size; // if(!capInsets.equals(Rect::ZERO)) //此处的if判断应该去掉,直接赋值给_capInsetsInternal { _capInsetsInternal = capInsets; } if (_scale9Enabled) { this->createSlicedSprites(); } //... }
原因:
setSpriteFrame时,默认传入的capInsets是zero,注意_insetRight ,_insetBottom 的值
void Scale9Sprite::setSpriteFrame(SpriteFrame * spriteFrame, const Rect& capInsets) { Sprite * sprite = Sprite::createWithTexture(spriteFrame->getTexture()); this->updateWithSprite(sprite, spriteFrame->getRect(), spriteFrame->isRotated(), spriteFrame->getOffset(), spriteFrame->getOriginalSize(), capInsets); // Reset insets this->_insetLeft = capInsets.origin.x; // == 0 this->_insetTop = capInsets.origin.y;// == 0 this->_insetRight = _originalSize.width - _insetLeft - capInsets.size.width; //== width this->_insetBottom = _originalSize.height - _insetTop - capInsets.size.height;// ==height }
然后cocosbuilder加载scale9sprite时,顺序调用setInsetLeft(0), setInsetTop(0), setInsetRight(0), setInsetBottom(0)
解析ccb的代码如下:
void Scale9SpriteLoader::onHandlePropTypeFloat(Node * pNode, Node * pParent, const char * pPropertyName, float pFloat, CCBReader * ccbReader) { if(strcmp(pPropertyName, PROPERTY_INSETLEFT) == 0) { ((cocos2d::ui::Scale9Sprite *)pNode)->setInsetLeft(pFloat); } else if(strcmp(pPropertyName, PROPERTY_INSETTOP) == 0) { ((cocos2d::ui::Scale9Sprite *)pNode)->setInsetTop(pFloat); } else if(strcmp(pPropertyName, PROPERTY_INSETRIGHT) == 0) { ((cocos2d::ui::Scale9Sprite *)pNode)->setInsetRight(pFloat); } else if(strcmp(pPropertyName, PROPERTY_INSETBOTTOM) == 0) { ((cocos2d::ui::Scale9Sprite *)pNode)->setInsetBottom(pFloat); } else { NodeLoader::onHandlePropTypeFloat(pNode, pParent, pPropertyName, pFloat, ccbReader); } }
4个函数都会调用updateCapInset,并在其中调用setCapInsets,在setCapInsets中调用updateWithSprite和重新计算_insetRight ,_insetBottom的值,
那么问题来了,执行到setInsetRight(0)时:
void Scale9Sprite::setCapInsets(const Rect& capInsets) { Size contentSize = this->_contentSize; this->updateWithSprite(this->_scale9Image, _spriteRect, _spriteFrameRotated, _offset, _originalSize, capInsets); // 这里传入的capInsets = (0,0, origin.width,0),此值不等于zero,在updateWithSprite中会赋值给_capInsetsInternal this->_insetLeft = capInsets.origin.x; this->_insetTop = capInsets.origin.y; this->_insetRight = _originalSize.width - _insetLeft - capInsets.size.width; this->_insetBottom = _originalSize.height - _insetTop - capInsets.size.height; this->setContentSize(contentSize); }
然后再在最后一次调用 setInsetBottom(0)时,capInsets==zero,因为有
if(!capInsets.equals(Rect::ZERO))判断,不会覆盖_capInsetsInternal,那么_capInsetsInternal就成了一个错误的临时值(0,0, origin.width,0),其实我们要的应该是最后一次调用后的值zero,即使用默认的九宫格缩放
// If there is no specified center region if ( _capInsetsInternal.equals(Rect::ZERO) ) { // log("... cap insets not specified : using default cap insets ..."); _capInsetsInternal = Rect(width /3, height /3, width /3, height /3); }
当_capInsetsInternal == (0,0, origin.width,0)时,默认值也不会被使用,那么九宫格缩放当然是错误的啦。
所以在updateWithSprite中,// if(!capInsets.equals(Rect::ZERO)) //此处的if判断应该去掉,直接赋值给_capInsetsInternal ,避免多次setCapInset时使用中间的临时值。
=======================华丽的分割线=======================
2. 创建的九宫格图片偏移了几个像素
https://github.com/cocos2d/cocos2d-x/issues/13564如图(右为普通sprite,左为scale9sprite):
createSlicedSprites接口中计算offsetPosition时:
void Scale9Sprite::createSlicedSprites() { float width = _originalSize.width; float height = _originalSize.height; Vec2 offsetPosition(ceil(_offset.x + (_originalSize.width - _spriteRect.size.width) / 2), ceil(_offset.y + (_originalSize.height - _spriteRect.size.height) / 2)); //... }
此处计算偏移时为什么要向上取整,总之我不是很明白,希望有人能解释一下,谢谢。
- 导致的问题:
生成的九宫格图片偏移了几个像素,这个问题一般情况下不明显,我是在使用plist拼图时发现, 九宫格图片下方出现了其他图片的条纹,自己图片的上方少了几排像素。
然后找到上面的代码,去掉ceil后,发现恢复了一些,如图(左图还是能看到上方的角少了点):
把ceil换成floor后,发现正常了,如图(texturepacker打开shape outlines):
那么问题来了:
按我的理解此处不应该使用ceil,也不应该使用floor,但为什么使用floor后才是正常的。有空的朋友可以使用texturepacker打个纹理图集测试一下,把shape outlines勾选上就能看到图片的矩形区域,看看你们创建出来的scale9sprite矩形区域是否发生了偏移。
=======================华丽的分割线=======================
相关文章推荐
- cocos2dx 交叉编译 iconv库 protobuf库
- Cocos2d-x中PageView使用中的问题
- cmake clion 构建cocos2dx 应用程序并编译ios mac android
- 【笔记】试玩 cocos2d-x-3.0beta on android
- cocos2dx出现 Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1)
- cocos2dx 粒子系统CCParticleSystem
- cocos2dx 中各种运动和速度
- Cocos2dx 中的CCCallFunc,CCCallFuncN,CCCallFuncND,CCCallFuncO比较
- CCScale9Sprite的用法
- cocos2dx入门
- [cocos2dx]随机数的使用
- 滴答UI编辑器初实战,实现cocos2dx的支持
- 成都公司诚聘cocos2dx(有wp经验)
- cocos2dx中js绑定的回调
- 第一次写博客,多多关照,
- xcode创建cocos2dx模版 关于couldn't add 'com.apple.XcodeGenerated' tag错误
- cocos2d-x 重力感应 加速器的使用
- cocos2d-x 一些有用的函数
- cocos2dx radiogrouop实现