3

I want to display a SKSpriteNode in front of a CAShapeLayer and this is the code that I am using :

import SpriteKit
import GameplayKit
import UIKit

class GameScene: SKScene {

    let progressLayer = CAShapeLayer()

    override func didMove(to view: SKView) {

        let circle = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        view.addSubview(circle)
        view.sendSubview(toBack: circle)

        progressLayer.frame = view.bounds
        progressLayer.path = progressPath.cgPath

        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.strokeColor = UIColor.green.cgColor
        progressLayer.lineWidth = 20.0

        let animation2 = CABasicAnimation(keyPath: "strokeEnd")
        animation2.fromValue = 0.0
        animation2.toValue = 1.0
        animation2.duration = 1
        animation2.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)

        progressLayer.add(animation2, forKey: "drawLineAnimation")

        circle.layer.addSublayer(progressLayer)

        var popup = SKSpriteNode(imageNamed: "popupWorking.png")
        popup.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        popup.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
        popup.size = CGSize(width: 400, height: 200)
        popup.zPosition = 10
        self.addChild(popup)
    }
}

But when I run the code, the CAShapeLayer appears in front of the SKSpriteNode, how do I make the SKSpriteNode appear in front of the CAShapeLayer?

Oliver Redeyoff
  • 177
  • 2
  • 14

2 Answers2

2

You'll need to change your view hierarchy at the view controller level. By default the view controller's view is an SKView. If you want to place a different UIView behind your SKView, you will need to adjust the view hierarchy.

Modify the view controller's view to be a UIView instead of an SKView. Then, add your shape layer's view as a subview to this main view. After that, add your SKView as a subview of the main view.

Your new view hierarchy should look like this:

View Controller
    – view (UIView)
        - circle view (UIView with your CAShapeLayer as a sublayer)
        - spritekit view (SKView)

While it is possible to combine UIKit and SpriteKit in this way, it may be easier to stay within the SpriteKit world and recreate the circle animation using SKSpriteNodes instead of a CAShapeLayer.

nathangitter
  • 9,607
  • 3
  • 33
  • 42
0

Here is a playground that shows one way of doing it. I followed suggestion by @nathan .

Yellow line is drawn using SKShapeNode. The red shadow needs to be animated behind it and hence uses CAShapeLayer. (Note: I needed to mix the two as animating shadow path would be much more complicated in pure Sprite)

import SpriteKit
import PlaygroundSupport

private func invert(_ path: CGMutablePath)  -> CGPath {
    var rotation = CGAffineTransform(scaleX: 1.0, y: -1.0);
    return path.copy(using: &rotation)!;
}

let bounds = CGRect(x: 0, y: 0, width: 400, height: 200)
let uiview = UIView(frame: bounds)
let pathview = UIView(frame: bounds)
let skview = SKView(frame: bounds)

PlaygroundPage.current.liveView = uiview


// Define the path
let path: CGMutablePath = CGMutablePath();
path.move(to: CGPoint(x:0, y:0))
path.addLine(to: CGPoint(x:200, y:100))


// Use CAShapeLayer to draw the red line
var pathLayer: CAShapeLayer = CAShapeLayer()
pathLayer.position = CGPoint(x: uiview.bounds.minX, y: uiview.bounds.minY + 200)
pathLayer.path = invert(path)
pathLayer.strokeColor = UIColor.red.cgColor
pathLayer.fillColor = nil
pathLayer.lineWidth = 10.0
pathLayer.lineJoin = kCALineJoinBevel
pathLayer.lineCap = kCALineCapRound
pathLayer.zPosition = 3;
let strokeAnimation = CABasicAnimation(keyPath: "strokeAnimation")
strokeAnimation.duration = 2;
strokeAnimation.fromValue = 0;
pathview.layer.addSublayer(pathLayer);
pathLayer.add(strokeAnimation, forKey: "strokePath");

uiview.addSubview(pathview)

//Use SKShapeNode to draw the yellow line
let pathShape: SKShapeNode = SKShapeNode(path: path);
pathShape.strokeColor = .white;
pathShape.lineWidth = 2.0;
pathShape.zPosition = 20;

// Create SK Scene
let scene = SKScene(size: CGSize(width: 400, height: 200))
scene.scaleMode = SKSceneScaleMode.aspectFill
scene.size = skview.bounds.size
scene.addChild(pathShape);
scene.backgroundColor = UIColor.clear;
skview.backgroundColor = UIColor.clear


skview.presentScene(scene);
uiview.insertSubview(skview, aboveSubview: pathview)
MP Droid
  • 155
  • 1
  • 9