在SpriteKit中,SKCropNode对SKShapeNode没有任何影响。

9

我一直试图使用SKCropNode将蒙版应用于SKShapeNode,但迄今为止没有成功。认为这是一个SpriteKit的错误 - 以下是代码片段:

SKNode* contentNode = [SKNode node];

// picture - use an image bigger than 50x50
SKSpriteNode *pictureNode = [SKSpriteNode spriteNodeWithImageNamed:@"tree"];

// triangle
SKShapeNode* triangleNode = [SKShapeNode node];
UIBezierPath* triangleNodeBezierPath = [[UIBezierPath alloc] init];
[triangleNodeBezierPath moveToPoint:CGPointMake(0.0, 0.0)];
[triangleNodeBezierPath addLineToPoint:CGPointMake(0.0, 100.0)];
[triangleNodeBezierPath addLineToPoint:CGPointMake(50.0, 100.0)];
[triangleNodeBezierPath closePath];

triangleNode.path = triangleNodeBezierPath.CGPath;
triangleNode.fillColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1];

// create a mask
SKSpriteNode *mask = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size: CGSizeMake(50, 50)]; //50 by 50 is the size of the mask

// create a SKCropNode
SKCropNode *cropNode = [SKCropNode node];

[cropNode addChild: contentNode];
[cropNode setMaskNode: mask];

[self addChild: cropNode];
[contentNode addChild:pictureNode]; // pictureNode is being cropped
[contentNode addChild:triangleNode]; // triangleNode is not

cropNode.position = CGPointMake( CGRectGetMidX (self.frame), CGRectGetMidY (self.frame));

有人能提供这个问题的解决方法吗?非常感谢!

3个回答

9
这一天大部分时间都在困扰我。我计划创建一个类似于 Tony Chamblee 的 TCProgressTimer 优秀的定时器。然而,由于我的应用程序使用了多个进度计时器,我不想为不同分辨率设计数十种不同大小的精灵。
我的解决方案是将 SKShapeNode 对象转换为 SKSpriteNode 对象。最终,我不得不回到基础并使用核心图形来完成繁重的工作。我相信这是一种比较混乱的方式,但我想要快速的结果,以动态地创建对象,使其类似于使用 SKShapeNode 时获得的结果。
目前,我只对创建圆形对象感兴趣,所以我就像这样做:
-(SKSpriteNode *)createSpriteMatchingSKShapeNodeWithRadius:(float)radius color:(SKColor *)color {
    CALayer *drawingLayer = [CALayer layer];
    CALayer *circleLayer = [CALayer layer];
    circleLayer.frame = CGRectMake(0,0,radius*2.0f,radius*2.0f);
    circleLayer.backgroundColor = color.CGColor;
    circleLayer.cornerRadius = circleLayer.frame.size.width/2.0;
    circleLayer.masksToBounds = YES;


    [drawingLayer addSublayer:circleLayer];

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(circleLayer.frame.size.width, circleLayer.frame.size.height), NO, [UIScreen mainScreen].scale);
    CGContextSetAllowsAntialiasing(UIGraphicsGetCurrentContext(), TRUE);
    CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), [UIColor clearColor].CGColor);
    CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0,0,circleLayer.frame.size.width,circleLayer.frame.size.height));
    [drawingLayer renderInContext: UIGraphicsGetCurrentContext()];

    UIImage *layerImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImage:layerImage]];


    return sprite;
}

生成的精灵现在可以像预期的那样由SKCropNode进行遮罩。由于这些精灵都是在场景开始之前生成的,所以我没有注意到性能问题。然而,如果您正在动态生成多个节点,则我想象这种方法非常低效。我很想听听其他用户的解决方案。希望有所帮助。-DC

3
叹气,我也遇到了这个问题。我已经在提交反馈申请。很不幸,SKShapeNode不能与SKCropNode一起使用。但幸运的是,对我来说我只需要一个矩形,所以我可以使用SKSpriteNode。 - Mobile Ben
@MobileBen 在SKShapeNode和CAShapeLayer中,CGPaths无法像线编辑一样进行属性编辑,这是我见过的2D绘图和动画技术中最令人惊讶的疏忽之一。而这种明显的缺失在SpriteKit的2D交互、渲染、操作和使用方面也普遍存在。这让我想起了我的烹饪:一份混杂着Bubble-n-Squeak的半熟食物,用纸盘子端上桌;最好用叉匙一起享用。 - Confused
苹果公司构建了通用的产品以供大众使用。不幸的是,对于游戏来说,你经常会遇到专门的情况。再加上工作在SK上的团队可能并不是用它来构建游戏,而只是演示。所以他们并不真正了解所有这些项目将如何在现场使用。他们似乎只有一个功能清单。这就是我放弃SK的原因之一。SK的性能实际上并不好。我还怀疑随着游戏越来越大,它的扩展性也不会很好。现在我已经拥有了我的新引擎,并且我的游戏运行速度更快,开发也更容易了。 - Mobile Ben
或许(在苹果公司)缺失的是一种定义自己为游戏和游戏性能的渴望。没有迹象表明他们关心或关注游戏市场。作为移动游戏设备的成功对于苹果来说主要是偶然的——这是将用户交互性能、先发优势和品牌力量融合在一起,占领市场,并且程序员和消费者寻求满足他们的游戏需求的结果。 - Confused

5

我在我的应用程序中有类似的任务。我需要根据用户输入绘制多个不规则形状,然后将它们用作裁剪节点的掩模。

对我有效的解决方案是:

  1. 创建具有所需路径的SKShapeNode

  2. 使用SKView方法textureFromNode:crop:从中检索SKTexture

  3. 从该纹理创建SKSpriteNode。

  4. 将SKSprite节点用作掩码。


这是最佳实践,让我清楚 SKView.textureFromNode:crop: 的作用。;-) - Juguang
1
我在使用 textureFromNode:crop: 时遇到了问题:即使我传递的矩形是合理的,它仍然返回 nil。我正在处理一个 SKShapeNode,因此没有可用的 size 属性;我为裁剪矩形传递了一个预定大小。另一方面,textureFromNode: 可以正常工作(但纹理位置不正确)。 - Nicolas Miari

2
你的标题是正确的。我还发现,在CropNode的层次结构中有一个ShapeNode也会影响其上面的子节点。我进行了一个快速实验。你可以创建一个新的游戏项目并自己尝试。通过注释掉其中一行addChild:shapeContent,你可以看到它如何影响飞船图像的裁剪。
正如DoctorClod指出的那样,当前的解决方案似乎是确保cropNode的所有子节点都是SpriteNodes。
-(void)didMoveToView:(SKView *)view {

SKSpriteNode* colorBackground = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(800, 600)];

SKSpriteNode *spaceshipImage = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];

SKShapeNode* shapeContent = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 200, 100)];
shapeContent.fillColor = [SKColor greenColor];

SKSpriteNode *maskShape  = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(500, 100)];

SKCropNode *cropNode = [SKCropNode new];

[cropNode addChild:colorBackground];
[cropNode addChild:shapeContent];     // comment this one out
[cropNode addChild:spaceshipImage];
[cropNode addChild:shapeContent];     // or comment this one out

[cropNode setMaskNode:maskShape];

cropNode.position = CGPointMake(CGRectGetMidX (self.frame), CGRectGetMidY(self.frame));
[self addChild:cropNode];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接