在Spritekit中扩展圆形剪切过渡效果

时间:2017-02-01 16:31:24

标签: swift sprite-kit ios10 sktransition blend-mode

我试图获得类似于任天堂在精灵套件中的超级马里奥运行游戏中的过渡效果

enter image description here

我只想要一个圆形切口来扩展显示下一个场景或只是揭示当前场景。这不是标准iOS精灵工具包转换之一。

我使用覆盖整个场景的完全黑色图层并使用SKCropNode为展开的圆圈设置动画以显示场景。

以下是didMove(to view: SKView)

中的代码
let fullScreen = SKSpriteNode(color: .black, size: self.size)
let mask = SKSpriteNode(color: .black, size: self.size)
let circle = SKShapeNode(circleOfRadius: self.size.height / 2)
circle.fillColor = .white
circle.blendMode = .subtract
circle.setScale(0.001)
circle.isHidden = true
circle.name = "circleShape"
mask.addChild(circle)

let crop = SKCropNode()
crop.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
crop.maskNode = mask
crop.name = "cropNode"
crop.addChild(fullScreen)
crop.zPosition = 100

self.addChild(crop)

let waitAction = SKAction.wait(forDuration: 2.0)
let callAction = SKAction.run({
    let cropNode = self.childNode(withName: "cropNode") as! SKCropNode
    let maskNode = cropNode.maskNode as! SKSpriteNode
    let circleNode = maskNode.childNode(withName: "circleShape") as! SKShapeNode
    circleNode.isHidden = false
    let scaleAction = SKAction.scale(to: 2.0, duration: 2.0)
    scaleAction.timingFunction = scaleAction.easeInQuartic
    circleNode.run(scaleAction, completion: {
        cropNode.removeFromParent()
    })
})
let seqAction = SKAction.sequence([waitAction,callAction])
self.run(seqAction)

这可以在模拟器中运行,但不能在设备上运行(带有最新iOS 10的iPad pro 2016)。在设备上,缩放操作完成后,不会出现扩展圆圈,黑色覆盖层会消失。

我的问题:

1)为什么这不能在设备上工作,只能在模拟器上工作?

2)有没有更好更有效的方法来实现sprite kit中的这种转换?

提前致谢。

2 个答案:

答案 0 :(得分:1)

可能有100种不同的方法来实现这一目标。我的方式比你的好吗?可能不是,但这对我来说在模拟器和iPad上都适用。

只需转换到持续时间为0.0的场景,然后从didMove运行此乐趣(查看:)

你需要一个单独的圆形图像的原因是它在放大时保持其漂亮的清晰边缘

bgOverlay只是从一个完全黑屏开始,然后应用seudo过渡

func circleTransition() {

    let bgMask = SKSpriteNode(texture: SKTexture(imageNamed: "bg_mask"), color: .clear, size: CGSize(width: self.size.width, height: self.size.height))
    bgMask.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
    bgMask.zPosition = 5000
    self.addChild(bgMask)

    let transitionCircle = SKSpriteNode(texture: SKTexture(imageNamed: "transition_circle"), color: .clear, size: CGSize(width: 13, height: 13))
    transitionCircle.position = CGPoint.zero
    transitionCircle.zPosition = 1
    bgMask.addChild(transitionCircle)

    let bgOverlay = SKSpriteNode(texture: SKTexture(imageNamed: "bg_overlay"), color: .clear, size: CGSize(width: self.size.width, height: self.size.height))
    bgOverlay.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
    bgOverlay.zPosition = 5001
    self.addChild(bgOverlay)

    bgMask.run(SKAction.sequence([SKAction.scale(to: 100.0, duration: 2.0), SKAction.removeFromParent()]))
    bgOverlay.run(SKAction.sequence([SKAction.fadeOut(withDuration: 0.1), SKAction.removeFromParent()]))
}

bg

transition_circle

bg_mask

答案 1 :(得分:0)

我最终使用带有片段着色器的SKSpriteNode。以下是主场景中的代码:

let fullScreen = SKSpriteNode(color: UIColor.clear, size: CGSize(width: self.size.width, height: self.size.height))
fullScreen.position = CGPoint(x: self.size.width / 2.0, y: self.size.height / 2.0)
fullScreen.zPosition = 200
self.addChild(fullScreen)
let shader = SKShader(fileNamed: "transitionShader.fsh")
shader.attributes = [SKAttribute(name: "a_sprite_size", type: .vectorFloat2),
                     SKAttribute(name:"a_duration", type: .float)]
fullScreen.shader = shader
let spriteSize = vector_float2(Float(fullScreen.frame.size.width),Float(fullScreen.frame.size.height))
fullScreen.setValue(SKAttributeValue(vectorFloat2: spriteSize),forAttribute: "a_sprite_size")
fullScreen.setValue(SKAttributeValue(float: Float(mainGameTransitionDuration)), forAttribute: "a_duration")

以下是名为transitionShader.fsh

的文件中的着色器代码
#define M 1000.0 // Multiplier

void main()
{
    float aspect = a_sprite_size.y / a_sprite_size.x;
    float u = v_tex_coord.x;
    float v = v_tex_coord.y * aspect;
    vec2 uv = vec2(u,v) * M;
    vec2 center = vec2(0.60,0.55 * aspect) * M;
    float t = u_time / a_duration;
    if ( t < 1.0 )
    {
        float easeIn = pow(t,5.0);
        float radius = easeIn * 2.0 * M;
        float d = length(center - uv) - radius;
        float a = clamp(d, 0.0, 1.0);
        gl_FragColor = vec4(0.0,0.0,0.0, a);
    }
    else
    {
        gl_FragColor = vec4(0.0,0.0,0.0,0.0);
    }
}

似乎无问题,在CPU或内存上看起来并不昂贵。