cocos2d-x 文本 优化
不得不说,CCLabelTTF是一个很鸡肋的组件,在2dx for ios库里面,它的底层使用了UIKit包来实现文本显示,但其显示特性较弱,几乎不可扩展。比如实现文字阴影,描边还有另一个更2的问题,当我们采用2dx的多分辨解决方案时,如
CCDirector::sharedDirector()->setContentScaleFactor(2.0); 这时的所有的文字都模糊不清,惨不忍睹。很多人此时会考虑抛弃ios默认字体,该自定义字体库,但几千个字符(包括诸如日文,韩文等)全部整合起来还是很麻烦的
首先,我们追根溯源,查看2dx源代码,发现CCLabelTTF底层是由CCImage来渲染的,核心代码
《CCImage.mm》
static bool _initWithString(const char * pText, cocos2d::CCImage::ETextAlign eAlign, const char * pFontName, int nSize, tImageInfo* pInfo)
关于代码细节此处不再详解,大致是用NSString 的draw方法来绘制文字,这里我们仿造来写一个
1.在《CCImage.h》中加入这些方法
//UIImage转CCImage bool initWithUIImage(void* uimg); /** 获取文字显示大小,注意,只是获取文字的显示区域大小,这个大小是 依据文字fontsize,是否换行等属性来确定,也就是说,调用该方法,文字并未渲染!*/ static CCSize getImageStringSize(const char *pText,float fontSize, ccColor3B fillColor,ccColor4B shadowColor,bool isShadow,CCSize dimensions,CCTextAlignment hAlignment ,CCVerticalTextAlignment vAlignment); //渲染文字 void initWithShadowLabel( const char * pText,float fontSize,ccColor3B fillColor,ccColor4B shadowColor,bool isShadow = true,CCSize dimensions = CCSizeZero,CCTextAlignment h = kCCTextAlignmentLeft,CCVerticalTextAlignment v = kCCVerticalTextAlignmentTop);
2.
1 // UIImage转CCImage 2 3 bool CCImage::initWithUIImage(void* uimg) 4 5 { 6 7 CGImageRef CGImage = [(UIImage *)uimg CGImage]; 8 9 tImageInfo info = {0}; 10 11 bool bRet = _initWithImage(CGImage, &info); 12 13 if (bRet) 14 15 { 16 17 m_nHeight = (short)info.height; 18 19 m_nWidth = (short)info.width; 20 21 m_nBitsPerComponent = info.bitsPerComponent; 22 23 m_bHasAlpha = info.hasAlpha; 24 25 m_bPreMulti = info.isPremultipliedAlpha; 26 27 m_pData = info.data; 28 29 } 30 31 return bRet; 32 33 } 34 35 CCSize CCImage::getImageStringSize(const char *pText,float fontSize, ccColor3B fillColor,ccColor4B shadowColor,bool isShadow,CCSize dimensions,CCTextAlignment hAlignment ,CCVerticalTextAlignment vAlignment) 36 37 { 38 39 ETextAlign align; 40 41 //获取文本对齐方式 42 43 if (kCCVerticalTextAlignmentTop == vAlignment) 44 45 { 46 47 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignTop 48 49 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignTopLeft : CCImage::kAlignTopRight; 50 51 } 52 53 elseif (kCCVerticalTextAlignmentCenter == vAlignment) 54 55 { 56 57 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignCenter 58 59 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignLeft : CCImage::kAlignRight; 60 61 } 62 63 elseif (kCCVerticalTextAlignmentBottom == vAlignment) 64 65 { 66 67 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignBottom 68 69 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignBottomLeft : CCImage::kAlignBottomRight; 70 71 } 72 73 else 74 75 { 76 77 CCAssert(false, "Not supported alignment format!"); 78 79 } 80 81 //此处可以自己修改成其他字体样式,经过比较,我们选择使用系统加粗字体 82 83 UIFont *font = [UIFont boldSystemFontOfSize:fontSize]; 84 85 NSString *str = [NSString stringWithUTF8String:pText]; 86 87 CGSize dim, constrainSize; 88 89 constrainSize.width = dimensions.width; 90 91 constrainSize.height = dimensions.height; 92 93 // create the font ,这块代码 从引擎拷贝过来 94 95 if (font) 96 97 { 98 99 dim = _calculateStringSize(str, font, &constrainSize); 100 101 } 102 103 // compute start point 104 105 int startH = 0; 106 107 if (constrainSize.height > dim.height) 108 109 { 110 111 // vertical alignment 112 113 unsigned int vAlignment = (align >> 4) & 0x0F; 114 115 if (vAlignment == ALIGN_TOP) 116 117 { 118 119 startH = 0; 120 121 } 122 123 else if (vAlignment == ALIGN_CENTER) 124 125 { 126 127 startH = (constrainSize.height - dim.height) / 2; 128 129 } 130 131 else 132 133 { 134 135 startH = constrainSize.height - dim.height; 136 137 } 138 139 } 140 141 return CCSizeMake(dim.width, dim.height - startH); 142 143 } 144 145 146 147 void CCImage::initWithShadowLabel(const char *pText,float fontSize, ccColor3B fillColor,ccColor4B shadowColor,bool isShadow,CCSize dimensions,CCTextAlignment hAlignment ,CCVerticalTextAlignment vAlignment) 148 149 { 150 151 do { 152 153 CGFloat scaleFactor = CCDirector::sharedDirector()->getContentScaleFactor(); 154 155 //获取文本对齐方式 156 157 ETextAlign align; 158 159 if (kCCVerticalTextAlignmentTop == vAlignment) 160 161 { 162 163 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignTop 164 165 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignTopLeft : CCImage::kAlignTopRight; 166 167 } 168 169 elseif (kCCVerticalTextAlignmentCenter == vAlignment) 170 171 { 172 173 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignCenter 174 175 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignLeft : CCImage::kAlignRight; 176 177 } 178 179 elseif (kCCVerticalTextAlignmentBottom == vAlignment) 180 181 { 182 183 align = (kCCTextAlignmentCenter == hAlignment) ? CCImage::kAlignBottom 184 185 : (kCCTextAlignmentLeft == hAlignment) ? CCImage::kAlignBottomLeft : CCImage::kAlignBottomRight; 186 187 } 188 189 else 190 191 { 192 193 break; 194 195 } 196 197 UIFont *font = [UIFont boldSystemFontOfSize:fontSize]; 198 199 NSString *str = [NSString stringWithUTF8String:pText]; 200 201 CC_BREAK_IF(!font); 202 203 CGSize dim, constrainSize; 204 205 constrainSize.width = dimensions.width; 206 207 constrainSize.height = dimensions.height; 208 209 210 211 // create the font 212 213 214 215 dim = _calculateStringSize(str, font, &constrainSize); 216 217 218 219 // compute start point 220 221 int startH = 0; 222 223 if (constrainSize.height > dim.height) 224 225 { 226 227 // vertical alignment 228 229 unsigned int vAlignment = (align >> 4) & 0x0F; 230 231 if (vAlignment == ALIGN_TOP) 232 233 { 234 235 startH = 0; 236 237 } 238 239 else if (vAlignment == ALIGN_CENTER) 240 241 { 242 243 startH = (constrainSize.height - dim.height) / 2; 244 245 } 246 247 else 248 249 { 250 251 startH = constrainSize.height - dim.height; 252 253 } 254 255 } 256 257 // adjust text rect 258 259 if (constrainSize.width > 0 && constrainSize.width > dim.width) 260 261 { 262 263 dim.width = constrainSize.width; 264 265 } 266 267 if (constrainSize.height > 0 && constrainSize.height > dim.height) 268 269 { 270 271 dim.height = constrainSize.height; 272 273 } 274 275 276 277 CGSize size; 278 279 size.width = dim.width * scaleFactor; 280 281 size.height = dim.height * scaleFactor; 282 283 284 285 UIGraphicsBeginImageContextWithOptions(size,false,scaleFactor); 286 287 288 289 CGContextRef context = UIGraphicsGetCurrentContext(); 290 291 CC_BREAK_IF(!context); 292 293 294 295 // CGContextSetLineWidth(context, 2); 296 297 ccColor4F fillColor4f = ccc4FFromccc3B(fillColor); 298 299 //设置文本颜色 300 301 CGContextSetRGBFillColor(context, fillColor4f.r, fillColor4f.g, fillColor4f.b, fillColor4f.a); 302 303 // 这个地方 绘制文本阴影 304 305 ccColor4F sColor4F =ccc4FFromccc4B(shadowColor); 306 307 float sColor[4] = {sColor4F.r, sColor4F.g, sColor4F.b, sColor4F.a}; 308 309 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 310 311 CGColorRef color = CGColorCreate(colorSpace,sColor); 312
313 CGColorSpaceRelease(colorSpace); 314 315 if (isShadow) 316 317 { 318 319 //设置文字阴影 320 321 CGContextSetShadowWithColor(context, CGSizeMake(1.0, 1.0), 0.0, color); 322 323 } 324 325 // draw in context 326 327 CGContextScaleCTM(context, scaleFactor, scaleFactor);
328 CGColorRelease(color);
329 //绘制换行文本 330 331 [str drawInRect:CGRectMake(0, startH, dim.width, dim.height) withFont:font lineBreakMode:(UILineBreakMode)UILineBreakModeWordWrapalignment:align]; 332 333 // [str drawAtPoint:CGPointMake(0.0, 0.0) withFont:font]; // 画单行文本 334 335 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 336 337 UIGraphicsEndImageContext(); 338 339 this->initWithUIImage(image); 340 341 } 342 343 while (0); 344 345 }
剩下的就是把CCImage转成CCtexture2D,然后交给CCSprite显示