能否在Sprite Kit中使用圆形(SKShapeNode)作为遮罩?

11

我试图在一个Sprite Kit项目中创建一个圆形掩模。我像这样创建了圆形(将其定位在屏幕的中心位置):

SKCropNode *cropNode = [[SKCropNode alloc] init];

SKShapeNode *circleMask = [[SKShapeNode alloc ]init];
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, CGRectGetMidX(self.frame), CGRectGetMidY(self.frame), 50, 0, M_PI*2, YES);
circleMask.path = circle;
circleMask.lineWidth = 0;
circleMask.fillColor = [SKColor blueColor];
circleMask.name=@"circleMask";

在代码的进一步部分,我将其设置为cropNode的遮罩:

[cropNode setMaskNode:circleMask];

... 但是内容显示的不是圆形,而是以正方形的形式出现掩模。

我能否使用 SKShapeNode 作为掩模,或者需要使用图像?

5个回答

13

经过大量的艰辛努力、在网络上寻找以及在Xcode中进行实验,我终于有了一个非常巧妙的解决方法。

请记住,这是一个非常恶心的hack - 但你可以把它归咎于Sprite Kit中SKShapeNode的实现。将填充添加到路径会导致以下情况:

  • 在场景中添加一个额外的节点
  • 路径变得无法遮罩 - 它似乎出现在遮罩上方
  • 使任何非SKSpriteNode兄弟节点无法遮罩(例如SKLabelNode

这并不是最理想的状态。

Tony Chamblee进度计时器的启发,'解决方法'是完全放弃填充,仅使用路径的描边:

SKCropNode *cropNode = [[SKCropNode alloc] init];

SKShapeNode *circleMask = [[SKShapeNode alloc ]init];
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, CGRectGetMidX(self.frame), CGRectGetMidY(self.frame), 50, 0, M_PI*2, YES); // replace 50 with HALF the desired radius of the circle
circleMask.path = circle;
circleMask.lineWidth = 100; // replace 100 with DOUBLE the desired radius of the circle
circleMask.strokeColor = [SKColor whiteColor];
circleMask.name=@"circleMask";

[cropNode setMaskNode:circleMask];

如评论所说,您需要将半径设置为通常所需的一半,并将线宽度设置为半径的两倍。

希望苹果在未来能够解决这个问题;目前,这个方法是我发现的最好的解决方案(除了使用图像,如果您的遮罩需要动态,则不太适用)。


6

由于无法使用SKShapeNode作为遮罩,我决定将其转换为SKSpriteNode

以下是我的Swift代码:

let shape : SKShapeNode = ... // create your SKShapeNode
var view : SKView = ... // you can get this from GameViewController

let texture = view.textureFromNode(shape)
let sprite = SKSpriteNode(texture: texture)
sprite.position = ...

cropNode.mask = sprite

它确实有效 :)


看起来你需要在场景中添加一个未使用的形状节点。我建议你研究一下如何从CGPathUIBezierPath创建UIImage,然后从图像生成纹理。 - 0x141E
嗨0x141E,实际上我没有将shape(即SKShapeNode)添加到场景中。唯一会被保存的节点是sprite - Luca Angeletti
3
这个方案比被接受的那个更好。 - 0x141E

5

是的,在当前的Sprite-Kit实现中无法使用填充颜色的形状节点。我认为这是一个错误。

但是!

你总可以将形状渲染成纹理并将其用作蒙版!

例如,让edge是先前创建的SKShapeNode。

首先,在将其添加到视图之前,将其呈现为纹理(在这种情况下,它将被清除另一个节点)

SKTexture *Mask = [self.view textureFromNode:edge];
[self addChild:edge]; //if you need physics borders

第二,
SKCropNode *cropNode = [[SKCropNode alloc] init];
[cropNode setMaskNode:[SKSpriteNode spriteNodeWithTexture:Mask]];
[cropNode addChild: [SKSpriteNode spriteNodeWithTexture:rocksTiles size:CGSizeMake(w,h)]];
cropNode.position = CGPointMake(Mask.size.width/2,Mask.size.height/2);
//note, anchorpoint of shape in 0,0, but rendered texture is in 0.5,0.5, so we need to dispose it
[self addChild:cropNode];

现在有些东西是可能的(iOS 8.1): int deviceOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];if (deviceOSVersion >= 8.0) treeS.fillTexture = [SKTexture textureWithImage:[UIImage imageNamed:@"treeS"]]; - djdance

1

对于这个问题,有一个略微尴尬的解决方案,我认为比其他提出的hack方法要好一些。只需将您的SKShapeNode包装在SKNode中即可。我还没有测试这可能会导致什么样的性能损失,但考虑到SKNode是非绘图的,我希望它不会太明显。

例如:

let background = SKSpriteNode(imageNamed: "Background")
let maskNode = SKShapeNode(path: MyPath)
let wrapperNode = SKNode()
let cropNode = SKCropNode()

wrapperNode.addChild(maskNode)
cropNode.maskNode = wrapperNode
cropNode.addChild(background)

0
将遮罩节点的 alpha 值设置为 .0 即可解决问题:
circleMask.alpha = .0;

编辑: 似乎仅适用于Mac OS。


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