CCRenderTextureで輪郭線を描く
cocos2dを使っていて、CCSpriteに輪郭線を付けたい!ということがよくある。
「輪郭線」「Outline」「Outline Stroke」などでググると、色々出てくるけどCCRenderTextureを使う方法がメジャーみたい。
ということで試してみた。
CCSpriteとCCLableTTF(CCSpriteのsubclass)ができればよかったので、CCSpriteのCategoryで作ってみた。
#import "CCSprite+OutlineStroke.h" @implementation CCSprite (OutlineStroke) - (void)createOutlineWithStroke:(float)stroke color:(ccColor3B)color { CGPoint center = ccp(self.texture.contentSize.width * self.anchorPoint.x + stroke, self.texture.contentSize.height * self.anchorPoint.y + stroke); float factor = [self isKindOfClass:[CCLabelTTF class]] ? CC_CONTENT_SCALE_FACTOR() : 1.0f; CCRenderTexture *render = [CCRenderTexture renderTextureWithWidth:self.texture.contentSize.width * factor + stroke*2 height:self.texture.contentSize.height* factor + stroke*2]; ccColor3B origColor = self.color; CGPoint origAnchor = self.anchorPoint; CGPoint origPos = self.position; float origScale = self.scale; ccBlendFunc origBlend = self.blendFunc; [self setBlendFunc:(ccBlendFunc) { GL_SRC_ALPHA, GL_ONE }]; NSInteger drawNum = 16; // 描画回数, この数値を大きくするとより滑らかになるが遅くなる [render begin]; self.color = color; self.scaleY *= -1; // CCRenderTextureは上下反転するのでFlipさせる // オリジナルの周囲にstrokeずつずらして描画 float radian = 0.0; for (int i=0; i<drawNum; i++) { self.position = ccpAdd(center, ccp(cosf(radian) * stroke, sinf(radian) * stroke)); [self visit]; radian += CC_DEGREES_TO_RADIANS(360.0f/drawNum); } // オリジナルを中心に描画 self.blendFunc = origBlend; self.color = origColor; self.position = center; [self visit]; [render end]; self.anchorPoint = origAnchor; self.position = origPos; self.scale = origScale; // アンチエイリアスに設定 // この設定をしないと、ジャギーが目立つ [render.sprite.texture setAntiAliasTexParameters]; // テクスチャをアウトライン付きのものと入れ替える self.texture = render.sprite.texture; self.textureRect = CGRectMake(render.sprite.textureRect.origin.x, render.sprite.textureRect.origin.y, render.sprite.textureRect.size.width / factor, render.sprite.textureRect.size.height / factor); }
イイね!
textureを入れ替えちゃう破壊的メソッドになっているので、
返り値をCCTexture2DかCCSpriteに書き換えて自分でセットする方が安全で使いやすいかも。
CCLabelTTFのときにだけvisitするときに、大きさが倍になってしまう。なんでやねん。
対処するために、factorという変数を用意してrenderTextureのサイズを合わせている。
もしこれを動的にやるなら、CCRenderTextureは使わずに
visitをオーバーライドして同じことをさせればできると思う。
その方法ならサイズは関係ないし、CCNodeでもできそう。