完成此任务的代码非常简单:
var cropNode = SKCropNode()
var shape = SKShapeNode(rectOf: CGSize(width:100,height:100))
shape.fillColor = SKColor.orange
var shape2 = SKShapeNode(rectOf: CGSize(width:25,height:25))
shape2.fillColor = SKColor.red
shape2.blendMode = .subtract
shape.addChild(shape2)
cropNode.addChild(shape)
cropNode.position = CGPoint(x:150,y:170)
cropNode.maskNode=shape
container.addChild(cropNode)
相同的代码,相同的iOS,不同的结果=没有bueno
答案 0 :(得分:2)
这是一个使用着色器为您生成maskNode的方法:
func generateMaskNode(from mask:SKNode) -> SKNode
{
var returningNode : SKNode!
autoreleasepool
{
let view = SKView()
//First let's flatten the node
let texture = view.texture(from: mask)
let node = SKSpriteNode(texture:texture)
//Next apply the shader to the flattened node to allow for color swapping
node.shader = SKShader(fileNamed: "shader.fsh")
let texture2 = view.texture(from: node)
returningNode = SKSpriteNode(texture:texture2)
}
return returningNode
}
它要求你创建一个名为shader.fsh的文件,里面的代码如下所示:
void main() {
// Find the pixel at the coordinate of the actual texture
vec4 val = texture2D(u_texture, v_tex_coord);
// If the color value of that pixel is 0,0,0
if (val.r == 0.0 && val.g == 0.0 && val.b == 0.0) {
// Turn the pixel off
gl_FragColor = vec4(0.0,0.0,0.0,0.0);
}
else {
// Otherwise, keep the original color
gl_FragColor = val;
}
}
要使用它,它需要使用黑色像素而不是alpha作为确定裁剪内容的方法,因此以下是您的代码现在的样子:
var cropNode = SKCropNode()
var shape = SKShapeNode(rectOf: CGSize(width:100,height:100))
shape.fillColor = SKColor.orange
var shape2 = SKShapeNode(rectOf: CGSize(width:25,height:25))
shape2.fillColor = SKColor.orange
shape2.blendMode = .subtract
shape.addChild(shape2)
let mask = generateMaskNode(from:shape)
cropNode.addChild(shape)
cropNode.position = CGPoint(x:150,y:170)
cropNode.maskNode=mask
container.addChild(cropNode)
减法在模拟器而不是设备上工作的原因是因为模拟器减去alpha通道,而设备没有。该设备实际上表现正常,因为不假设alpha被减去,所以假设它被忽略。
请注意,您不必选择黑色作为裁剪颜色,您可以更改着色器以允许您选择的任何颜色,只需更改线条:
if (val.r == 0.0 && val.g == 0.0 && val.b == 0.0)
你想要的颜色。 (就像你的情况一样。你可以说r = 0 g = 1 b = 0只能在绿色上裁剪)
Result of above code on a device
编辑:我想要注意减去混合不是必需的,这也可行:
var cropNode = SKCropNode()
var shape = SKShapeNode(rectOf: CGSize(width:100,height:100))
shape.fillColor = SKColor.orange
var shape2 = SKShapeNode(rectOf: CGSize(width:25,height:25))
shape2.fillColor = SKColor.black
shape2.blendMode = .replace
shape.addChild(shape2)
let mask = generateMaskNode(from:shape)
cropNode.addChild(shape)
cropNode.position = CGPoint(x:150,y:170)
cropNode.maskNode=mask
container.addChild(cropNode)
现在问题是我无法测试,这是我的功能甚至需要。
理论上的下列代码应该可以工作,因为它正在用上面的代码替换基础像素,所以理论上alpha应该转移。如果有人可以测试这个,请告诉我它是否有效。
var cropNode = SKCropNode()
var shape = SKShapeNode(rectOf: CGSize(width:100,height:100))
shape.fillColor = SKColor.orange
var shape2 = SKShapeNode(rectOf: CGSize(width:25,height:25))
shape2.fillColor = SKColor(red:0,green:0,blue:0,alpha:0)
shape2.blendMode = .replace
shape.addChild(shape2)
cropNode.addChild(shape)
cropNode.position = CGPoint(x:150,y:170)
cropNode.maskNode= shape.copy() as! SKNode
container.addChild(cropNode)
替换只替换颜色而不是alpha
答案 1 :(得分:0)
由于SpriteKit似乎并不具备反向屏蔽(以某种方式适用于设备),我认为以下是最接近答案的内容:
let background = SKSpriteNode(imageNamed:"stocksnap")
background.position = CGPoint(x:65, y:background.size.height/2)
addChild(background)
let container = SKNode()
let cropNode = SKCropNode()
let bgCopy = SKSpriteNode(imageNamed:"stocksnap")
bgCopy.position = background.position
cropNode.addChild(bgCopy)
let cover = SKShapeNode(rect: CGRect(x:0,y:0,width:200,height:200))
cover.position = CGPoint(x:80,y:150)
cover.fillColor = SKColor.orange
container.addChild(cover)
let highlight = SKShapeNode(rectOf: CGSize(width:100,height:100))
highlight.position = CGPoint(x:cover.position.x+cover.frame.size.width/2,y:cover.position.y+cover.frame.size.height/2)
highlight.fillColor = SKColor.red
cropNode.maskNode = highlight
container.addChild(cropNode)
addChild(container)
Here is a screenshot from a device using above technique
这只是使用背景的副本,对其进行遮罩,并将其覆盖在相同位置以创建反向遮罩效果。在您想要复制屏幕上的内容的情况下,您可以使用以下内容:
func captureScreen() -> SKSpriteNode {
var image = UIImage()
if let view = self.view {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
if let imageFromContext = UIGraphicsGetImageFromCurrentImageContext() {
image = imageFromContext
}
UIGraphicsEndImageContext()
}
let texture = SKTexture(image:image)
let sprite = SKSpriteNode(texture:texture)
//scale is applicable if using fixed screen sizes that aren't the actual width and height
sprite.scale(to: CGSize(width:size.width,height:size.height))
sprite.anchorPoint = CGPoint(x:0,y:0)
return sprite
}
希望有人找到更好的方法,或者对SpriteKit进行更新以支持反向屏蔽,但与此同时,这对我的用例很有用。