2012-11-21 14 views
5

में गैर आयताकार CCNode के लिए मैं इस गतिशील रूप से की तरह एक रूपरेखा बनाने की जरूरत:रूपरेखा (स्ट्रोक) Cocos2d

Red 2px outline

नहीं CCSprite के लिए, लेकिन कई एनिमेटेड एक CCNode में एकजुट CCSprites के लिए।

  1. एक बनावट (जैसे AS3 में canvasBitmapData.draw(sourceDisplayObject))
  2. जिसके परिणामस्वरूप बनावट
  3. साथ CCSprite बनाने स्प्राइट tinting रंग की रूपरेखा तैयार करने और इसे थोड़ा
  4. स्केलिंग को CCNode की सामग्री को कॉपी: मैं के बारे में सोच रहा हूँ
  5. नोड में अन्य स्प्राइट के पीछे स्प्राइट रखने

मैं पता नहीं कैसे चरण 1 प्रदर्शन करने के लिए है और शायद यह बनावट के अपारदर्शी चारों ओर "true stroke" आकर्षित करने के लिए तेजी से होता है चरण 3 में टिंट-स्केल के बजाय पिक्सल?

+0

नहीं एक विकल्प एक स्ट्रोक के साथ PNG बनाने के लिए? – Setrio

+0

@ सेत्रियो: यह है। मैंने रूपरेखा के रंग को बदलने में सक्षम होने के लिए विभिन्न तरीकों की कोशिश की (जैसे उपरोक्त या यहां तक ​​कि एक शेडर के साथ) ... लेकिन परिणामस्वरूप फ्रेम को रूपरेखा और पृष्ठभूमि और रूपरेखा और स्प्राइट के बीच अलियाज्ड सीमा की वजह से निराशाजनक पाया गया । एंटी-एलियासिंग सुविधाओं का उपयोग करके, मेरे ट्रस्टी फ़ोटोशॉप के साथ इसे समाप्त कर दिया। – YvesLeBorg

+0

@ सेत्रियो: नहीं, उदाहरण के हाथ अलग-अलग sprites और एनिमेशन के दौरान घूर्णन के उदाहरण की कल्पना करो। मैं प्री-रेंडर स्प्राइट शीट्स के बारे में जानता हूं, लेकिन गेम हीरो के बहुत सारे परिवर्तनीय एनिमेटेड हिस्सों के साथ आरपीजी है। और शैली के लिए स्ट्रोक बहुत महत्वपूर्ण है (उदाहरण स्प्राइट खेल से नहीं है)। –

उत्तर

2

मैं पूरी तरह इस प्रश्न के लिए एक जवाब पोस्ट करने के लिए भूल गया था। एक बहुत चिकनी स्ट्रोक के लिए कोड यहाँ है। यह तेज़ नहीं है लेकिन पहले आईपैड पर कुछ बड़े sprites के लिए अच्छा काम किया।

विचार स्प्राइट के चारों ओर छोटे रंग और धुंधले गेंदों को आकर्षित करना है और उन्हें अपने स्वयं के बनावट पर रखना है। इसका उपयोग सीसीएनोड और सीसीएसप्रेट दोनों के लिए किया जा सकता है। कोड एंकर पॉइंट्स को भी बदल देता है क्योंकि परिणामी स्प्राइट्स की थोड़ी बड़ी चौड़ाई और ऊंचाई होगी।

परिणामस्वरूप रूपरेखा (शरीर और 2 हाथ, के बारे में iPad1 पर 0.3s):

outline

सफेद गेंदों का उदाहरण:

CCNode श्रेणी, Cocos2d-iPhone 2.1 के लिए:

@implementation CCNode (Outline) 

- (CCSprite*) outline 
{ 
    return [self outlineRect:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height)]; 
} 

- (CCSprite*) outlineRect:(CGRect)rect 
{ 
    NSInteger gap = dscale(4); 
    CGPoint positionShift = ccp(gap - rect.origin.x, gap - rect.origin.y); 
    CGSize canvasSize = CGSizeMake(rect.size.width + gap * 2, rect.size.height + gap * 2); 

    CCRenderTexture* renderedSpriteTexture = [self renderTextureFrom:self shiftedFor:positionShift onCanvasSized:canvasSize]; 
    CGSize textureSize = renderedSpriteTexture.sprite.contentSize; 
    CGSize textureSizeInPixels = renderedSpriteTexture.sprite.texture.contentSizeInPixels; 

    NSInteger bitsPerComponent = 8; 
    NSInteger bytesPerPixel = (bitsPerComponent * 4)/8; 
    NSInteger bytesPerRow = bytesPerPixel * textureSizeInPixels.width; 
    NSInteger myDataLength = bytesPerRow * textureSizeInPixels.height; 

    NSMutableData* buffer = [[NSMutableData alloc] initWithCapacity:myDataLength]; 
    Byte* bytes = (Byte*)[buffer mutableBytes]; 

    [renderedSpriteTexture begin]; 
    glReadPixels(0, 0, textureSizeInPixels.width, textureSizeInPixels.height, GL_RGBA, GL_UNSIGNED_BYTE, bytes); 
    [renderedSpriteTexture end]; 

    //SEE ATTACHMENT TO GET THE FILES 
    NSString* spriteFrameName; 
    if (IS_IPAD) spriteFrameName = (CC_CONTENT_SCALE_FACTOR() == 1) ? @"10f.png" : @"20f.png"; 
    else spriteFrameName = (CC_CONTENT_SCALE_FACTOR() == 1) ? @"5f.png" : @"10f.png"; 

    CCSprite* circle = [CCSprite spriteWithSpriteFrameName:spriteFrameName]; 
    circle.anchorPoint = ccp(0.48, 0.48); 
    float retinaScale = (CC_CONTENT_SCALE_FACTOR() == 1) ? 1.0 : 0.5; 

    CCRenderTexture* strokeTexture = [CCRenderTexture renderTextureWithWidth:textureSize.width height:textureSize.height pixelFormat:kCCTexture2DPixelFormat_RGBA8888]; 
    [strokeTexture beginWithClear:0 g:0 b:0 a:0]; 
    for (NSInteger x = 0; x < textureSizeInPixels.width; x++) 
    { 
     for (NSInteger y = 0; y < textureSizeInPixels.height; y++) 
     { 
      NSInteger idx = y * bytesPerRow + x * bytesPerPixel + 3; 
      NSInteger w = 1; 
      if (bytes[idx] <= 254) 
      { 
       BOOL shouldBeStroked = NO; 
       for (NSInteger nx = -w; nx <= w; nx++) 
       { 
        for (NSInteger ny = -w; ny <= w; ny++) 
        { 
         if (x + nx < 0 || y + ny < 0 || x + nx >= textureSizeInPixels.width || y + ny >= textureSizeInPixels.height) 
          continue; 

         if (bytes[idx + nx * bytesPerPixel + ny * bytesPerRow] == 255) 
         { 
          shouldBeStroked = YES; 
          break; 
         } 
        } 
       } 

       if (shouldBeStroked == YES) 
       { 
        circle.position = ccp(x * retinaScale, y * retinaScale); 
        [circle visit]; 
       } 
      } 
     } 
    } 
    [strokeTexture end]; 

    CCSprite* resultSprite = [CCSprite spriteWithTexture:strokeTexture.sprite.texture]; 
    [resultSprite.texture setAntiAliasTexParameters]; 
    resultSprite.flipY = YES; 

    if ([self isKindOfClass:[CCSprite class]]) { 
     CGPoint oldAnchorInPixels = ccp(roundf(self.contentSize.width * self.anchorPoint.x), roundf(self.contentSize.height * self.anchorPoint.y)); 
     resultSprite.anchorPoint = ccp((oldAnchorInPixels.x + gap)/resultSprite.contentSize.width, (oldAnchorInPixels.y + gap)/resultSprite.contentSize.height); 
     resultSprite.position = self.position; 
    } else { //CCNode 
     resultSprite.anchorPoint = CGPointZero; 
     resultSprite.position = ccpAdd(self.position, ccp(rect.origin.x - gap, rect.origin.y - gap)); 
    } 
    return resultSprite; 
} 

- (CCRenderTexture*) renderTextureFrom:(CCNode*)node shiftedFor:(CGPoint)posShift onCanvasSized:(CGSize)size 
{ 
    SoftAssertion(!CGSizeEqualToSize(size, CGSizeZero), @"node has zero size"); 

    BOOL isSprite = [node isMemberOfClass:[CCSprite class]]; 
    CGPoint apSave = node.anchorPoint; 
    CGPoint posSave = node.position; 
    BOOL wasVisible = node.visible; 

    CCRenderTexture* rtx = [CCRenderTexture renderTextureWithWidth:size.width 
                  height:size.height 
                 pixelFormat:kCCTexture2DPixelFormat_RGBA8888]; 
    [rtx beginWithClear:0 g:0 b:0 a:0]; 

    node.anchorPoint = CGPointZero; 
    node.position = posShift; 
    node.visible = YES; 

    if (isSprite) [node visit]; 
    else [[self cloneCCNode:node] visit]; 

    node.anchorPoint = apSave; 
    node.position = posSave; 
    node.visible = wasVisible; 

    [rtx end]; 
    return rtx; 
} 

- (CCNode*) cloneCCNode:(CCNode*)source 
{ 
    CCNode* clone = [CCNode node]; 

    void (^copyCCNodeProperties)(CCNode*, CCNode*) = ^(CCNode* source, CCNode* clone) 
    { 
     clone.visible = source.visible; 
     clone.rotation = source.rotation; 
     clone.position = source.position; 
     clone.anchorPoint = source.anchorPoint; 
     clone.zOrder = source.zOrder; 
     clone.tag = source.tag; 
    }; 

    for (CCNode* srcSubnode in source.children) { 

     CCNode* subNode; 

     if ([srcSubnode isMemberOfClass:[CCSprite class]]) { 
      CCSprite* srcSprite = (CCSprite*)srcSubnode; 
      subNode = [CCSprite spriteWithTexture:srcSprite.texture]; 
      CCSprite* subSprite = (CCSprite*)subNode; 
      subSprite.flipX = srcSprite.flipX; 
      subSprite.flipY = srcSprite.flipY; 
      subSprite.displayFrame = srcSprite.displayFrame; 
      subSprite.opacity = srcSprite.opacity; 
     } 
     else if ([srcSubnode isMemberOfClass:[CCLabelTTF class]]) { 
      CCLabelTTF* srcLabel = (CCLabelTTF*)srcSubnode; 
      subNode = [CCLabelTTF labelWithString:srcLabel.string fontName:srcLabel.fontName fontSize:srcLabel.fontSize dimensions:srcLabel.dimensions hAlignment:srcLabel.horizontalAlignment vAlignment:srcLabel.verticalAlignment]; 
      CCSprite* subLabel = (CCSprite*)subNode; 
      subLabel.flipX = srcLabel.flipX; 
      subLabel.flipY = srcLabel.flipY; 
      subLabel.color = srcLabel.color; 
     } 
     else { 
      subNode = [self cloneCCNode:srcSubnode]; 
     } 

     copyCCNodeProperties(srcSubnode, subNode); 
     [clone addChild:subNode]; 
    } 
    copyCCNodeProperties(source, clone); 

    return clone; 
} 
+0

सीसीटीयूएल क्या है? क्या आप अपने इस्तेमाल का संदर्भ दे रहे हैं? –

+0

@ KeremBaydoğan ओह, क्षमा करें, हाँ। इसे उत्तर में जोड़ा गया। –

1

मेरे पास एक सामान्य उद्देश्य कार्य है जिसे मैंने विभिन्न स्रोतों से बनाया है (मुझे यह कहने में शर्म आती है कि मैं यहां संदर्भ नहीं दे सकता)। यह एक सीसीएसप्रेट लेता है, एक स्ट्रोक बनाएं जिसे आप इसके पीछे रख सकते हैं और एक सीसीआरेंडरटेक्चर में वापस आ सकते हैं। यदि पारित होने वाले स्प्राइट में बच्चे हैं (जैसा कि तुम्हारा हो सकता है) मुझे कोई कारण नहीं दिखता कि यह वही नहीं करेगा जो आप चाहते हैं, लेकिन मैंने कोशिश नहीं की है।

यहाँ यह मामले में है यह काम करता है:

@implementation Cocosutil 

+(CCRenderTexture*) createStrokeForSprite:(CCSprite*)sprite size:(float)size color:(ccColor3B)cor 
{ 
    CCRenderTexture* rt = [CCRenderTexture renderTextureWithWidth:sprite.texture.contentSize.width+size*2 height:sprite.texture.contentSize.height+size*2]; 
    CGPoint originalPos = [sprite position]; 
    ccColor3B originalColor = [sprite color]; 
    BOOL originalVisibility = [sprite visible]; 
    [sprite setColor:cor]; 
    [sprite setVisible:YES]; 
    ccBlendFunc originalBlend = [sprite blendFunc]; 
    [sprite setBlendFunc:(ccBlendFunc) { GL_SRC_ALPHA, GL_ONE }]; 
    CGPoint bottomLeft = ccp(sprite.texture.contentSize.width * sprite.anchorPoint.x + size, sprite.texture.contentSize.height * sprite.anchorPoint.y + size); 
    CGPoint positionOffset = ccp(sprite.texture.contentSize.width * sprite.anchorPoint.x - sprite.texture.contentSize.width/2,sprite.texture.contentSize.height * sprite.anchorPoint.y - sprite.texture.contentSize.height/2); 
    CGPoint position = ccpSub(originalPos, positionOffset); 

    [rt begin]; 
    for (int i=0; i<360; i+=30) 
    { 
     [sprite setPosition:ccp(bottomLeft.x + sin(CC_DEGREES_TO_RADIANS(i))*size, bottomLeft.y + cos(CC_DEGREES_TO_RADIANS(i))*size)]; 
     [sprite visit]; 
    } 
    [rt end]; 
    [sprite setPosition:originalPos]; 
    [sprite setColor:originalColor]; 
    [sprite setBlendFunc:originalBlend]; 
    [sprite setVisible:originalVisibility]; 
    [rt setPosition:position]; 
    return rt; 
} 

@end 

और यहाँ कोड है, जहां मैं इसका इस्तेमाल होता है:

- (id) initWithSprite:(CCSprite*)sprite color:(ccColor3B)color strokeSize:(float)strokeSize strokeColor:(ccColor3B)strokeColor { 
    self = [super init]; 

    if (self != nil) { 
     strokeColor_ = strokeColor; 
     strokeSize_ = strokeSize; 
     CCRenderTexture *stroke = [CocosUtil createStrokeForSprite:sprite size:strokeSize color:strokeColor]; 
     [self addChild:stroke z:kZStroke tag:kStroke]; 
     [self addChild:sprite z:kZLabel tag:kLabel]; 
     [self setContentSize:[sprite contentSize]]; 
    }  

    return self; 
} 
संबंधित मुद्दे