Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocos2d iphone cocos2d中非矩形CCNode的轮廓(笔划)_Cocos2d Iphone_Ccsprite_Stroke_Ccnode - Fatal编程技术网

Cocos2d iphone cocos2d中非矩形CCNode的轮廓(笔划)

Cocos2d iphone cocos2d中非矩形CCNode的轮廓(笔划),cocos2d-iphone,ccsprite,stroke,ccnode,Cocos2d Iphone,Ccsprite,Stroke,Ccnode,我需要动态创建一个这样的大纲: 不是一个CCSprite,而是多个动画CCSprite合并在一个CCNode中。我在想: 将CCNode的内容复制到纹理(如AS3中的canvasBitmapData.draw(sourceDisplayObject)) 使用生成的纹理创建CCSprite 将精灵着色为轮廓颜色,并将其放大一点 将精灵放置在节点中其他精灵的后面 我不知道如何执行步骤1。也许在第3步中,在纹理的不透明像素周围绘制“”比在着色比例上绘制“”更快?我有一个通用函数,是从各种来源构建的(

我需要动态创建一个这样的大纲:

不是一个CCSprite,而是多个动画CCSprite合并在一个CCNode中。我在想:

  • 将CCNode的内容复制到纹理(如AS3中的
    canvasBitmapData.draw(sourceDisplayObject)
  • 使用生成的纹理创建CCSprite
  • 将精灵着色为轮廓颜色,并将其放大一点
  • 将精灵放置在节点中其他精灵的后面

  • 我不知道如何执行步骤1。也许在第3步中,在纹理的不透明像素周围绘制“”比在着色比例上绘制“”更快?

    我有一个通用函数,是从各种来源构建的(我不好意思说我不能在这里引用)。它所做的是使用一个CCSprite,创建一个可以放在后面的笔划,然后返回到CCRenderTexture中。如果传来的精灵有孩子(就像你的孩子一样),我看不出它有什么理由不做你想做的,但我没有试过

    这里是它的工作情况:

    @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
    

    我完全忘了发布这个问题的答案。这是一个非常平滑的笔划的代码。虽然速度不快,但对于第一台iPad上的几个大精灵来说效果很好

    我们的想法是在精灵周围画一些颜色模糊的小球,然后把它们放在自己的纹理上。它可以用于CCNode和CCSprite。该代码还会移动定位点,因为生成的精灵将具有更大的宽度和高度

    生成的轮廓(身体和两只手,在iPad1上约为0.3秒):

    白色球示例:

    • 5f:
    • 10f:
    • 20f:
    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;
    }
    
    实施CCNode(大纲) -(CCSprite*)大纲 { return[self-outlineRect:CGRectMake(0,0,self.contentSize.width,self.contentSize.height)]; } -(CCSprite*)大纲视图:(CGRect)rect { NSInteger间隙=dscale(4); CGPoint positionShift=ccp(间隙-直线原点.x,间隙-直线原点.y); CGSize canvasSize=CGSizeMake(rect.size.width+gap*2,rect.size.height+gap*2); CCRenderTexture*renderedSpriteTexture=[self-RenderTextFrom:self-Shifted for:positionShift onCanvasSize:canvasSize]; CGSize textureSize=renderedSpriteTexture.sprite.contentSize; CGSize textureSizeInPixels=renderedSpriteTexture.sprite.texture.contentSizeInPixels; NSInteger bitsPerComponent=8; NSInteger bytesperpoixel=(bitsPerComponent*4)/8; NSInteger bytesPerRow=bytesPerPixel*textureSizeInPixels.width; NSInteger myDataLength=bytesPerRow*textureSizeInPixels.height; NSMutableData*缓冲区=[[NSMutableData alloc]initWithCapacity:myDataLength]; 字节*字节=(字节*)[缓冲区可变字节]; [renderedSpriteTexture begin]; glReadPixels(0,0,textureSizeInPixels.width,textureSizeInPixels.height,GL_RGBA,GL_无符号字节,字节); [renderedSpriteTexture结束]; //请参阅附件以获取文件 NSString*spriteFrameName; 如果(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]; 圆.锚点=ccp(0.48,0.48); 浮动视网膜比例=(CC_内容_比例系数()==1)?1.0:0.5; CCRenderTexture*strokeTexture=[CCRenderTexture renderTextureWithWidth:textureSize.width:textureSize.height pixelFormat:kCCTexture2DPixelFormat_RGBA8888]; [strokeTexture beginWithClear:0g:0b:0a:0]; 对于(NSInteger x=0;x如果(bytes[idx]不是使用笔划制作png的选项?@Setrio:是的。我尝试了多种方法(如上面建议的,甚至使用着色器-可以更改轮廓的颜色)…但发现结果帧令人失望,因为轮廓和背景之间以及轮廓和精灵之间的边界出现了锯齿。最后我用我的受托人photoshop使用了抗锯齿功能完成了这项工作。@Setrio:不,想象一下示例中的手是分开的精灵,在动画过程中旋转。我知道pre-r可爱的精灵床单,但游戏是RPG,有很多英雄的可变动画部分。笔划对风格非常重要(示例精灵不是来自游戏)。你检查过这个吗?@Setrio谢谢,我从你的链接获得了教程。它似乎可以帮助我完成步骤1。什么是CCTools?你是在引用自己的工具吗?@KeremBaydoğan oops,对不起,是的。将它添加到回复中。
    @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;
    }