是否可以在 Sprite Kit 中使用圆形(SKShapeNode)作为蒙版?
Posted
技术标签:
【中文标题】是否可以在 Sprite Kit 中使用圆形(SKShapeNode)作为蒙版?【英文标题】:Is it possible to use a circle (SKShapeNode) as a mask in Sprite Kit? 【发布时间】:2013-11-26 22:05:28 【问题描述】:我正在尝试在 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
作为蒙版,还是需要使用图像?
【问题讨论】:
【参考方案1】:经过大量的咒骂、搜索和在 Xcode 中的实验,我有了一个非常老套的修复方法。
请记住,这是一个非常讨厌的 hack - 但您可以将其归咎于 Sprite Kit 对 SKShapeNode
的实现。向路径添加填充会导致以下情况:
SKSpriteNode
兄弟节点不可屏蔽(例如SKLabelNode
s)
不是一个理想的状态。
受Tony Chamblee's progress timer的启发,“修复”是完全省去填充,只使用路径的描边:
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];
如上所述,您需要将半径设置为通常的一半,并将线宽设置为半径的两倍。
希望苹果将来会关注这一点;目前,这个 hack 是我找到的最好的解决方案(除了使用图像,如果你的面具需要是动态的,这真的不起作用)。
【讨论】:
【参考方案2】:是的,在当前的 Sprite-Kit 实现中不可能使用填充颜色的 shapenode。我认为这是一个错误。
但是!
您始终可以将形状渲染为纹理并将其用作遮罩!
例如,设 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"]];【参考方案3】:由于我不能使用 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
它确实有效:)
【讨论】:
看起来您需要在场景中添加一个未使用的形状节点。我建议您考虑从CGPath
或UIBezierPath
创建UIImage
。然后,您可以从图像生成纹理。
嗨 0x141E,实际上我没有将 shape(SKShapeNode)添加到场景中。唯一要保存的节点是sprite。
这是一个比公认的更好的解决方案【参考方案4】:
对于这个问题有一个稍微尴尬的解决方案,我认为它比围绕这个问题的任何有争议的 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)
【讨论】:
【参考方案5】:将掩码节点的 alpha 设置为 .0 即可:
circleMask.alpha = .0;
编辑: 似乎仅适用于 Mac OS。
【讨论】:
以上是关于是否可以在 Sprite Kit 中使用圆形(SKShapeNode)作为蒙版?的主要内容,如果未能解决你的问题,请参考以下文章