मैं पूरी तरह इस प्रश्न के लिए एक जवाब पोस्ट करने के लिए भूल गया था। एक बहुत चिकनी स्ट्रोक के लिए कोड यहाँ है। यह तेज़ नहीं है लेकिन पहले आईपैड पर कुछ बड़े sprites के लिए अच्छा काम किया।
विचार स्प्राइट के चारों ओर छोटे रंग और धुंधले गेंदों को आकर्षित करना है और उन्हें अपने स्वयं के बनावट पर रखना है। इसका उपयोग सीसीएनोड और सीसीएसप्रेट दोनों के लिए किया जा सकता है। कोड एंकर पॉइंट्स को भी बदल देता है क्योंकि परिणामी स्प्राइट्स की थोड़ी बड़ी चौड़ाई और ऊंचाई होगी।
परिणामस्वरूप रूपरेखा (शरीर और 2 हाथ, के बारे में iPad1 पर 0.3s):
सफेद गेंदों का उदाहरण:
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;
}
स्रोत
2014-12-10 01:40:05
नहीं एक विकल्प एक स्ट्रोक के साथ PNG बनाने के लिए? – Setrio
@ सेत्रियो: यह है। मैंने रूपरेखा के रंग को बदलने में सक्षम होने के लिए विभिन्न तरीकों की कोशिश की (जैसे उपरोक्त या यहां तक कि एक शेडर के साथ) ... लेकिन परिणामस्वरूप फ्रेम को रूपरेखा और पृष्ठभूमि और रूपरेखा और स्प्राइट के बीच अलियाज्ड सीमा की वजह से निराशाजनक पाया गया । एंटी-एलियासिंग सुविधाओं का उपयोग करके, मेरे ट्रस्टी फ़ोटोशॉप के साथ इसे समाप्त कर दिया। – YvesLeBorg
@ सेत्रियो: नहीं, उदाहरण के हाथ अलग-अलग sprites और एनिमेशन के दौरान घूर्णन के उदाहरण की कल्पना करो। मैं प्री-रेंडर स्प्राइट शीट्स के बारे में जानता हूं, लेकिन गेम हीरो के बहुत सारे परिवर्तनीय एनिमेटेड हिस्सों के साथ आरपीजी है। और शैली के लिए स्ट्रोक बहुत महत्वपूर्ण है (उदाहरण स्प्राइट खेल से नहीं है)। –